Blueprint Script to auto select a Spotify Account for a specific source/player to start playing music on.
(My) Purpose It’s really annoying to be out wondering around and jamming to some music through my phone on Spotify, but when a person back at home uses the (previous) script automations, it ‘steals’ my account and sets the device as the main-room (rather than my headphones) & with different music. so the ‘simple’ way around this would be use use one of the other Family accounts (in my subscription) to be dedicated to playing music in that location, however there are times when all the accounts need to be playing elsewhere. (and none-of the accounts are unused)
Solution This blueprint which performs the simple function of setting the source to either (of the following) and playing the specified playlist (stored in an input_text object)
- the account which is already playing in the main-room
- the first account (if there is one), which is not playing, and has the main-room source avaliable
Limitation
There is a big on here (and I think it’s reasonably well known, but is still important): Spotify must be logged into a source/player, or a computer on the local network must have the Spotify app open and be able to see the specified source for HA (and indeed the Sportify Web-API) to ‘see’ that source in the source_list.
- my current work around is that the main-room is a RiPi3 with docker-raspotify running multiple times, each with it’s own sign-in for all the linked accounts in HA. I hope to post the docker-compose.yaml file later to its GitHub page.
Source
(version 1)
# Copyright (c) 2022, Matthew Tilney
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
blueprint:
name: Spotify Select Player
description: >
Allows for automatic selection of a spotify account to be used with the specified source:
a) selects the current Spotify account already playing on the source,
b) select an account currently not playing from the (ordered) Spotify Accounts list
Dependencies: HA Spotify Intergration for at least 1 account (but mutiple supported, this is the whole point)
Issues: Sources are only avaliable in Home Assistant (viat the Spotify Intergration & Web-API) if:
1. The account is signed into the specific Spotify account on the source
2. A local App is currently open (and internet accessable) on a device on the same network as the source.
- Workaround on RiPi devices (yet to be posted - May2022), run mutiple raspotify docker containers on the same devices, with the same name, each signed in to a different account
domain: script
input:
source_name:
name: Source Name
description: Name of the source (must be avaliable in the source_list for each spotify player to work on that account)
selector:
text:
media_list:
name: Spotify Accounts
description: Spotify Accounts list (ordere list, 1st one is checked first) for Spotify which could use for playing music
default: {entity_id: []}
selector:
target:
entity:
integration: spotify
media_content:
name: Media Content as Input Text
description: The media content url for spotify, can be playlist album, or track fron a previously populated input_text helper
selector:
entity:
domain: input_text
test_mode_enabled:
name: Test Mode
description: Some actions (specificall the source select and play media) are skipped, and output of which entity would be used is written to the log (WARN level)
default: false
selector:
boolean:
variables:
spotify_accounts: !input 'media_list'
output_source: !input 'source_name'
media_content: !input 'media_content'
test_mode: !input 'test_mode_enabled'
alias: Spotify Select Player (blueprint)
sequence:
- service: homeassistant.update_entity
data: {}
target:
entity_id: >
{% if spotify_accounts is not defined %}{% set spotify_accounts = namespace(entity_id = integration_entities("spotify") ) %}{% endif %} {% set
output_source = 'spotify-player'%} {%- set spotifies = namespace(entities=[])
-%} {% for entity in states.media_player %}
{% if entity.entity_id in spotify_accounts.entity_id %}
{%- set spotifies.entities = spotifies.entities + [entity] -%}
{% set entities = spotifies.entities %}
{% endif %}
{% endfor %} {{ spotifies.entities | map(attribute='entity_id') | list
}}
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
- if:
- condition: not
conditions:
- condition: template
value_template: !input 'test_mode_enabled'
then:
- service: media_player.select_source
target:
entity_id: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Return the 1st spotify entity_id from
the found list#} {{ (potential_players.entities |
map(attribute='entity_id') | list)[0] }}
data:
source: !input 'source_name'
- delay:
hours: 0
minutes: 0
seconds: 2
milliseconds: 500
- service: media_player.play_media
data:
media_content_id: >
{{ states(media_content) }}
media_content_type: playlist
target:
entity_id: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Return the 1st spotify entity_id from
the found list#} {{ (potential_players.entities |
map(attribute='entity_id') | list)[0] }}
else:
- service: system_log.write
data:
level: warning
message: >
{# Determin which media play can be used for the current sctip#} {#
Convert input entity_id list into full spotify entites in the HA
setup #} {% set spotifies = namespace(entities=[]) -%} {% set
potential_players = namespace(entities=[])%} {% set spotify_list =
[] -%} {% for player in spotify_accounts.entity_id %} {% if player
in integration_entities("spotify")%} {# I don't like having to use a
2nd loop, when a way of getting full entity from entity_id as a
command is possiable, this bit will no longer be rquired #} {% for
player_entity in states.media_player %}{% if player_entity.entity_id
== player %} {% set spotifies.entities = spotifies.entities +
[player_entity] -%} {% set entities = spotifies.entities %} {%
endif %}{% endfor %}{% endif %}{% endfor %} {# Perform the specific
selections, 1st if the device is already playing on the source, 2nd
and spotify account not playing that also has acccess to the source
#} {% for player in (spotifies.entities |
selectattr('state','ne','idle') | selectattr('attributes.source',
'search', output_source) | list )%} {%- set
potential_players.entities = potential_players.entities + [player]
-%} {% endfor %} {% for player in (spotifies.entities |
selectattr('state','ne','playing') |
selectattr('attributes.source_list','search',output_source) | list
)%} {%- set potential_players.entities = potential_players.entities
+ [player] -%} {% endfor %} {# Write out to log file (for enabled
mode) #} List of spotify accounts (1st will be selected)
{{potential_players.entities | map(attribute='entity_id') | list }};
with the source set as: {{ output_source }}; the content will be {{states(media_content)}}- Testmode: {{ test_mode }}
logger: scripts.log
mode: single