Unfortunately no
FYI - just released a new version of the SpotifyPlus integration
[ 1.0.56 ] - 2024/09/19
- Updated underlying
spotifywebapiPython
package requirement to version 1.0.96.
FYI - just released a new version of the SpotifyPlus integration
[ 1.0.57 ] - 2024/09/20
- Added service
get_audiobook_favorites
to get a list of the audiobooks saved in the current Spotify user’s ‘Your Library’. - Added service
get_episode_favorites
to get a list of the episodes saved in the current Spotify user’s ‘Your Library’. - Updated underlying
spotifywebapiPython
package requirement to version 1.0.97.
This release fixes a bug related to Spotify Connect devices that define aliases (introduced with v1.0.93). This was causing TypeError: unsupported operand type(s) for &: 'str' and 'tuple'
exceptions if a device had aliases defined.
Hi @thlucas, thanks for working on this integration!
I try to understand how to connect to a dynamic Spotify Connect device (spotifyd) which is not bound to any account (zeroconf authentication, spotifyd calls it “discovery mode” in the log).
You describe here how to solve common Spotify Connect issues.
What is not clear to me is how to fill the the upcoming fields with the values from the response, e.g. if I run the spotifyplus.zeroconf_discover_devices service, how to use the response for the spotifyplus.zeroconf_device_connect service.
May I ask you to elaborate on this a bit? Thanks a lot!!
Regards,
meiser
@meiser
If you just want to re-activate the device, have a look at the Common Spotify Connect Issues wiki page (that you mentioned above), and scroll down to The Solution (for INDIVIDUAL devices)
topic heading. It gives specific details on how to take the returned parameters from the zeroconf_discover_devices
service and use them in the zeroconf_device_connect
service to awaken the specified device.
If you just want to start playing content on the device, you can use the Transfer Playback Service to awaken the device and transfer playback to it. Note that the refresh_device_list: true
parameter is required in order to re-awaken the device (if it needs it).
service: spotifyplus.player_transfer_playback
data:
entity_id: media_player.spotifyplus_john_s
device_id: "Office"
play: true
refresh_device_list: true
Please let me know if this works with spotifyd
or not. I have another user with a spotifyd
issue, but I think his is related more to a network configuration problem. I have never used spotifyd
before, so I am curious to see how it plays with the integration. It should work fine if spotifyd
truly supports Spotify Connect Zeroconf discovery and configuration.
The thing is (as I’m not an experienced HA user yet), how do I use the values? How can I use the returned values in the next service? What’s the purpose of the response variable?
I tried the zeroconf_device_connect
service in the developer tools, but it just returns “Unknown error”.
Log shows:
024-09-25 18:27:53.870 ERROR (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Error executing script. Error for call_service at pos 1:
2024-09-25 18:27:53.871 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140410510929936] Error handling message: Unknown error (home_assistant_error) sysadmin from 192.168.3.3 (Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36.0 (KHTML, like Gecko) Chrome/126.0.6478.185 Safari/537.36.0)
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/spotifywebapipython/zeroconfapi/zeroconfconnect.py", line 268, in _CheckResponseForErrors
raise SpotifyWebApiError(response.status_code, errMessage, methodName, response.reason, _logsi)
spotifywebapipython.spotifywebapierror.SpotifyWebApiError: SAM1001E - Spotify Web API returned an error status while processing the "Disconnect" method.
Status: 404 - Not Found
Message: ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/config/custom_components/spotifyplus/media_player.py", line 6909, in service_spotify_zeroconf_device_connect
result = zconn.Disconnect()
^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/spotifywebapipython/zeroconfapi/zeroconfconnect.py", line 908, in Disconnect
responseData:dict = self._CheckResponseForErrors(response, apiMethodName, endpoint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/spotifywebapipython/zeroconfapi/zeroconfconnect.py", line 285, in _CheckResponseForErrors
raise SpotifyZeroconfApiError(response.status_code, responseUTF8, methodName, response.reason, _logsi)
spotifywebapipython.zeroconfapi.spotifyzeroconfapierror.SpotifyZeroconfApiError: SAM1003E - Spotify ZeroConf API returned an error status while processing the "Disconnect" method.
Status: 404 - Not Found
Message: ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 28, in _handle_async_response
await func(hass, connection, msg)
File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 816, in handle_execute_script
script_result = await script_obj.async_run(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1795, in async_run
return await asyncio.shield(create_eager_task(run.async_run()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 463, in async_run
await self._async_step(log_exceptions=False)
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 527, in _async_step
self._handle_exception(
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 557, in _handle_exception
raise exception
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 525, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 763, in _async_call_service_step
response_data = await self._async_run_long_action(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 726, in _async_run_long_action
return await long_task
^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2761, in async_call
response_data = await coro
^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2804, in _execute_service
return await target(service_call)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/spotifyplus/__init__.py", line 1659, in service_handle_spotify_serviceresponse
response = await hass.async_add_executor_job(entity.service_spotify_zeroconf_device_connect, username, password, loginid, host_ipv4_address, host_ip_port, cpath, version, use_ssl, pre_disconnect, verify_device_list_entry)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 6926, in service_spotify_zeroconf_device_connect
raise HomeAssistantError(ex.Message)
homeassistant.exceptions.HomeAssistantError
And player_transfer_playback
always returns “Device not found” when using the device name.
If I try to connect to the spotifyd instance with the mini player and select it as a source, the spotifyd logs shows “Bad credentials”. I entered the credentials in the configuration section. My loginid is identical to my username according to the https://api.spotify.com/v1/me
returned values.
As I understand, spotifyd needs the OAuth token for authentication, not username/password, see here.
BTW, spotifyd works perfectly fine with the Spotify Android and desktop (Ubuntu) app.
@meiser
The “Bad Credentials” log entry sounds like spotifyd
is not able to connect to the underlying Spotify API. I know there were issues with librespot
being able to connect recently, but not sure if they have it sorted yet. The fact that spotifyd works correctly with Spotify Android / ubuntu apps is not relevant, as they (probably ?) use the Spotify Embedded Client to communicate with spotifyd (not Spotify Connect Zeroconf).
The SAM1003E - Spotify ZeroConf API returned an error status while processing the "Disconnect" method. Status: 404 - Not Found
indicates that the Zeroconf call to Spotify Connect failed for the given device; specifically that the resetUsers
Zeroconf entry-point could not be found (e.g. 404). This is probably related to the spotifyd / Bad Credentials
issue, in that spotifyd
cannot access the underlying Spotify Web API / Spotify Zeroconf API.
As for passing variables from service responses to another service, check out the Play First Context of Category Playlists script example.
The response variable contains the data returned from a service, IF the service returns data. This is optional, as some services do not return response data. Once the service completes, the service response variable will contain a dictionary of values that can be accessed by scripts and such. In the script example above, the output of the get_category_playlists
returns the following dictionary (abbreviated example):
user_profile:
country: US
display_name: Todd L
product: premium
type: user
result:
limit: 1
items:
- collaborative: false
description: "New jazz for open minds. Cover: Nubya Garcia"
external_urls:
spotify: https://open.spotify.com/playlist/37i9dQZF1DX7YCknf2jT6s
href: https://api.spotify.com/v1/playlists/37i9dQZF1DX7YCknf2jT6s
id: 37i9dQZF1DX7YCknf2jT6s
image_url: https://i.scdn.co/image/ab67706f000000021b3869f2e1d4f52bc5b034f9
images:
- url: https://i.scdn.co/image/ab67706f000000021b3869f2e1d4f52bc5b034f9
height: null
width: null
name: State of Jazz
owner:
display_name: Spotify
external_urls:
spotify: https://open.spotify.com/user/spotify
followers: {}
href: https://api.spotify.com/v1/users/spotify
id: spotify
type: user
uri: spotify:user:spotify
public: true
snapshotId: ZuzzQAAAAAC+o1HXn4U2iwUyk4m7lkfm
tracks:
href: https://api.spotify.com/v1/playlists/37i9dQZF1DX7YCknf2jT6s/tracks
total: 100
type: playlist
uri: spotify:playlist:37i9dQZF1DX7YCknf2jT6s
message: Jazz
The seconds service being executed accesses response data from the first service like so:
context_uri: "{{ search_result.result[\"items\"][0].uri }}"
This says to retrieve the URI value from the first (zero indexed) items collection value (e.g. search_result.result[\"items\"][0].uri
) and use it as the value to the context_uri
parameter for the player_media_play_context
service call.
This gets more into templating and how to write scripts, which is a pretty advanced topic for this thread. You might do some Googling on the HA template scripts, as well as check out the HA Developer Tools \ Template tool. I use it quite frequently when developing scripts / parsing output.
For example, copy / paste the following into the HA Developer Tools \ Template tool:
{## Imitate available variables: ##}
{% set episodes = {
"items": [
{
"is_externally_hosted": false,
"is_playable": true,
"name": "Armchair Anonymous: Grocery Store",
"release_date": "2024-08-23",
"resume_point": {
"fully_played": false,
"resume_position_ms": 21000,
},
"type": "episode",
"uri": "spotify:episode:3jkYh7UbNfdvqHDTJALOlT",
},
{
"is_externally_hosted": false,
"is_playable": true,
"name": "Dan Slepian (on The Sing Sing Files)",
"release_date": "2024-08-22",
"resume_point": {
"fully_played": false,
"resume_position_ms": 0,
},
"type": "episode",
"uri": "spotify:episode:3jkYh7UbNfdvqHDTJALOlT",
}
]
}%}
Episode 1 Info:
Episode Name = {{ episodes["items"][0].name }}
Release Date = {{ episodes["items"][0].release_date }}
Fully Played = {{ episodes["items"][0].resume_point.fully_played }}
Episode 2 Info:
Episode Name = {{ episodes["items"][1].name }}
Release Date = {{ episodes["items"][0].release_date }}
Fully Played = {{ episodes["items"][1].resume_point.fully_played }}
Will look something like this:
Hope it helps!
@thlucas, thanks a lot for your patience and guidance!!
I captured the traffic and checked the addUser
request.
From Spotify Android app to spotifyd:
Frame 158: 1096 bytes on wire (8768 bits), 1096 bytes captured (8768 bits)
Linux cooked capture v2
Internet Protocol Version 4, Src: 192.168.1.12, Dst: 192.168.1.4
Transmission Control Protocol, Src Port: 39182, Dst Port: 1234, Seq: 1, Ack: 1, Len: 1024
Hypertext Transfer Protocol
POST / HTTP/1.1\r\n
Accept-Encoding: gzip\r\n
Content-Length: 793\r\n
Connection: keep-alive\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Keep-Alive: 0\r\n
Host: 192.168.1.4:1234\r\n
User-Agent: Spotify/8.9.76.538 Android/34 (M2012K11AG)\r\n
\r\n
[Response in frame: 160]
[Full request URI: http://192.168.1.4:1234/]
File Data: 793 bytes
HTML Form URL Encoded: application/x-www-form-urlencoded
Form item: "action" = "addUser"
Form item: "userName" = "username_string"
[…]Form item: "blob" = "blob_string"
Form item: "clientKey" = "clientKey_string"
Form item: "loginId" = "loginId_string"
Form item: "deviceName" = "M2012K11AG"
Form item: "deviceId" = "deviceId_string"
Form item: "version" = "2.7.1"
From spotifyplus to spotifyd:
Frame 1278: 449 bytes on wire (3592 bits), 449 bytes captured (3592 bits)
Linux cooked capture v2
Internet Protocol Version 4, Src: 192.168.1.7, Dst: 192.168.1.4
Transmission Control Protocol, Src Port: 42274, Dst Port: 5354, Seq: 218, Ack: 1, Len: 377
[2 Reassembled TCP Segments (594 bytes): #1276(217), #1278(377)]
Hypertext Transfer Protocol
POST / HTTP/1.1\r\n
Host: 192.168.1.4:1234\r\n
User-Agent: python-requests/2.32.3\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept: */*\r\n
Connection: close\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 377\r\n
\r\n
[Response in frame: 1280]
[Full request URI: http://192.168.1.4:1234/]
File Data: 377 bytes
HTML Form URL Encoded: application/x-www-form-urlencoded
Form item: "action" = "addUser"
Form item: "version" = "2.7.1"
Form item: "tokenType" = "default"
Form item: "clientKey" = "clientKey_string"
Form item: "loginId" = "loginId_string"
Form item: "userName" = "username_string"
Form item: "blob" = "blob_string"
Could it be related to the User-Agent
header that I get Bad Credentials
as a user mentioned here something about a proper user-agent?
In my experience with the Spotify Connect Zeroconf addUser
call, the user-agent
is not relevant. All of the magic happens in the blob
parameter, which is encrypted. I also don’t see a tokenType
for the Spotify Android app flow, which is odd.
I would also suggest that you open a new issue if you want to pursue this further, so we can track details.
Thanks
I know it’s probably not a spotify plus issue, but can anyone help me out on where to look for the problem?
As often happens, this script doesn’t work and gives me the error you see below if I run it
data:
entity_id: media_player.spotifyplus_diegocampy
play: true
device_id: xxxxxxxxxx
refresh_device_list: true
action: spotifyplus.player_transfer_playback
## Errore nell'esecuzione dell'azione
A SpotifyConnectUsername parameter was not supplied; could not reactivate Spotify Connect device 'Bose (xxxxxxxxx)'
@Diegocampy
You need to set your Spotify Connect Username, Password, and LoginId values in the SpotifyPlus configuration options.
This was something that changed with the latest release of the spotifywebapiPython
due to changes made by Spotify and their login process.
The Spotify Connect Username and Password values are your Spotify credentials, and the Spotify Connect LoginID is the canonical form of your Spotify UserId. This value can easily be found using the Spotify Developer Web portal, using the Get Current Users profile service. Click on the Try It
button, then find the id
response value. It will look something like this: 31l77y75hfnhk79f7gk6jkk878mg
.
I begin to struggle to follow all the changes, every update I have to fix something … how would I do without you? thank you very much problem solved
My apologies for all of the changes, but Spotify is an ever-changing enviornment. Not to mention I have to try and accommodate other devices besides Bose.
Thanks for your patience.
I apologize, maybe I explained myself badly, I don’t complain to you, in general I was talking about any change in home assistant
No apologies necessary, I understand. Home Assistant is ever-changing as well. lol
Can i use SpotifyPlus with SpotCast instead Spotify Official Integration? Or Official is mandatory?
Thanks
@thlucas, I now switched to librespot
directly instead of using spotifyd
.
librespot
does not support the ResetUsers API, and, if I understand it correctly, therefore player_transfer_playback
fails. Could you make the Disconnect call optionally?
Traceback (most recent call last):
File "/config/custom_components/spotifyplus/media_player.py", line 5197, in service_spotify_player_transfer_playback
self.data.spotifyClient.PlayerTransferPlayback(deviceId, play, delay, refreshDeviceList=False)
File "/usr/local/lib/python3.12/site-packages/spotifywebapipython/spotifyclient.py", line 12154, in PlayerTransferPlayback
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
spotifywebapipython.spotifyapierror.SpotifyApiError: SpotifyApiError: SAM0001E - An unhandled exception occured while processing method "PlayerTransferPlayback".
SAM1003E - Spotify ZeroConf API returned an error status while processing the "Disconnect" method.
Status: 404 - Not Found
Message: ""
@cediqqu
Spotcast only supports the HA Spotify integration, and does not support SpotifyPlus.
@meiser
I have come to the same conclusion. I have spent the last 3 days learning about spotifyd, and how it works.
UPDATE - just saw you opened a wiki issue for this. I will respond there with comments. Thanks.
FYI - just released a new version of the SpotifyPlus integration
[ 1.0.59 ] - 2024/09/28
- Added support for devices that utilize spotifyd / librespot. See the wiki documentation for more information on how to configure support for spotifyD / librespot applications.
- Corrected the
media_content_id
attribute value when content is played on a Sonos device. Prior to this fix, the value was loaded from the Sonos Soco APIget_current_track_info.uri
value that contained thex-sonos-vli
value (e.g.x-sonos-vli:RINCON_38420B909DC801400:2,spotify:e934941535d7b182815bf688490ce8a8
). Themedia_content_id
attribute value now contains a true Spotify URI value (e.g.spotify:track:6kYyS9g4WJeRzTYqsmcMmM
). - Added the following extra state attribute:
sp_device_is_brand_sonos
- denotes the source device is a Sonos brand device (true) or not (false). - Added service
get_track
to get Spotify catalog information for a single track identified by its unique Spotify ID. - Added service
get_episode
to get Spotify catalog information for a single episode identified by its unique Spotify ID. - Updated underlying
spotifywebapiPython
package requirement to version 1.0.101.