Controlling Spotify from UI and via Alexa

Hi everyone,

based on @BTallack’s Harmony control box (see: Logitech Harmony Integration with @iandday's component) I have created a Spotify control box.

It allows to select the output target for Spotify using the “Spotify Connect” capability. Home Assistant is fully compatible with Spotify via it’s “spotify:” media_player component. Besides of selecting the output target via the HASS UI, it also adds a volume control and provides some intent_scripts, which allow Echo/Alexa to control your Spotify (even if Spotify is not currently playing via the Echo).

The UI control looks like this:

I’ve uploaded all needed config files to my bitbucket repository. Please be aware, that the configuration.yaml only holds the config lines, that are required for the Spotify stuff. Anything else has been removed for ease of reading. There might also be a better way to implement this, but for me it works fine and is very comfortable (especially with Alexa)… Imagine coming home from work and while storing your bike, you say: “Alexa, ask Home Assistant to play spotify on the livingroom PC” :slight_smile:

Git Repo:

Maybe someone finds this interesting and helpful.

1 Like

Looks like sensor.spotify_current_source is not configured.
And I think switching output device (media_player.select_source) with API is a premium feature (like most of the control):

Yup, just as the docs mention:

Controlling the Spotify component (pause, play, next, etc) requires a Premium account. If you do not have a Premium account, the component in the frontend will not show the controls.

I use the source output choice feature with Alexa, too.

My HA is called “DeeDee”. I use:
“Alexa, tell DeeDee to send music upstairs”
“Alexa, tell DeeDee to send music to the bathroom”

    - service: media_player.select_source
      entity_id: media_player.spotify
        source: >
          {%- set location = SpotifyLocation.lower() -%}
          {%- if location == "upstairs" or location == "the bedroom" or location == "bedroom" %}Master bedroom Echo Dot
          {%- elif location == "downstairs" -%}Livingroom Echo
          {%- elif location == "bathroom" or location == "the bathroom" or location == "to the bathroom" -%}Master bath dot
          {%- else -%}{{ states.media_player.spotify.attributes.source }}
          {%- endif %}
    type: plain
    text: Sending to {{SpotifyLocation}}

SpotifyLocation comes from the Alexa skill.


Good catch. I didn’t expect this to be “Premium” :smiley:

To play Spotify music on Alexa with voice control, here is another solution. You can download and convert Spotify to MP3 and then play converted MP3 format Spotify songs on Alexa freely.

Are you using Nabu casa integration to make intent working with Alexa ? Or are you using a custom skill ?

I did this using the Amazon Skills setup. It’d probably be easier to set up now using the Nabu Alexa integration.

Is it possible to share your lambda code ? I tried to make it work for months now… It could be awesome ! :slight_smile:

The AWS stuff is totally unfamiliar to me. If memory serves, I just copied the code from the docs. I haven’t touched it in ages. Here’s what I’ve got:

# -*- coding: utf-8 -*-
import os
import json
import logging
import urllib3

_debug = bool(os.environ.get('DEBUG'))

_logger = logging.getLogger('HomeAssistant-Intents')
_logger.setLevel(logging.DEBUG if _debug else logging.INFO)

def lambda_handler(event, context):
    """Handle incoming Alexa directive."""

    _logger.debug('Event: %s', event)

    base_url = os.environ.get('BASE_URL')
    assert base_url is not None, 'Please set BASE_URL environment variable'

        token = event.get('session', {}).get('user', {}).get('accessToken')
    except AttributeError:
        token = None

    if token is None and _debug:
        token = os.environ.get('LONG_LIVED_ACCESS_TOKEN')

    assert token, 'Could not get access token'

    verify_ssl = not bool(os.environ.get('NOT_VERIFY_SSL'))

    http = urllib3.PoolManager(
        cert_reqs='CERT_REQUIRED' if verify_ssl else 'CERT_NONE',
        timeout=urllib3.Timeout(connect=10.0, read=30.0)

    response = http.request(
            'Authorization': 'Bearer {}'.format(token),
            'Content-Type': 'application/json',
    if response.status >= 400:
        return {
            'event': {
                'payload': {
                    'type': 'INVALID_AUTHORIZATION_CREDENTIAL'
                    if response.status in (401, 403) else 'INTERNAL_ERROR',
    return json.loads('utf-8'))
1 Like