AppDaemon app that synchronizes rgb lights to the mood of the currently playing song in Home Assistant.
This app uses the Spotify API to extract the emotional mood value of the currently playing track. Each mood value lies on a 2D plane which is mapped to a color spectrum from which the color for the light is picked.
The built-in color maps used by the app look as follows. The horizontal axis ranges from negative (left) to positive (right) emotion while the vertical axis ranges from low (bottom) to high (top) energy. A sad, slow song is thus mapped to blue light while a happy, upbeat song is mapped to yellow light.
For this app to work, the following python package must be installed in the AppDaemon environment:
python_packages:
- spotipy
This app is available on HACS for easy installation and updating.
Important: HACS does not work by default if you are running AppDaemon with version 15 or newer of the Home
Assistant add-on. Refer to https://github.com/joBr99/nspanel-lovelace-ui/issues/1029#issue-1995332526 for a workaround.
Other AppDaemon installations should work with HACS as long as the app_dir
in your appdaemon.yaml
points to
appdaemon/apps/
within your Home Assistant config folder, as this is where HACS puts downloaded apps.
You can also install this app manually by simply downloading the spotify_mood_lights_sync
directory from inside the
apps
directory here to your local apps
directory. Then add the configuration to your apps/apps.yaml
.
The following shows a minimal example configuration (the spotify credentials are supplied via a secrets file here):
spotify_mood_lights_sync:
module: spotify_mood_lights_sync
class: SpotifyMoodLightsSync
client_id: !secret spotify_client_id
client_secret: !secret spotify_client_secret
media_player: media_player.spotify_johndoe
light: light.bedroom
You can switch the light synchronization on and off through Home Assistant by using
AppDaemon Callback Constraints. For
example, you can control the execution with an input_boolean
switch:
spotify_lights_sync:
constrain_input_boolean: input_boolean.spotify_lights_sync_toggle
The app expects a single entity name for the light
option. If you want to control multiple lights at once, you have to
create a group in Home Assistant and provide the group entity for the light
option.
The app only deals with the color attributes of the lights, leaving the brightness untouched. You can therefore control the brightness of your lights independently.
The app queries information from Spotify using the client id and client secret of a Spotify-Develop App for authentication. You can use the same values here that you use for the Spotify integration in Home Assistant.
The app supports media players from the spotify integration as well as generic media players.
Using a spotify media player is the default and thus no special config options must be set. Note that only the media players directly provided by the spotify integration will work in this mode.1 For other integrations, e.g. Sonos speakers, this may not work, and you should use search mode instead.
Since the Spotify integration in Home Assistant only polls the Spotify API every 30 seconds to detect when the currently playing song changes, the light synchronization may be delayed by up to 30 seconds in the worst case.
1: This mode is reliant on the media_content_id
attribute of the
media_player
containing the spotify track id (e.g. spotify:track:abcdefghijkl
) for the current song. If your
non-spotify media player supports this, you can also use direct mode.
The app can also listen on all non-spotify media players that support the media_title
and media_artist
state
attributes. In order to use such a player, add the mode: search
option to the app config. In this mode the app tries
to find the corresponding track in Spotify by title and artist before calculating the mood.
If a track cannot be found in Spotify the light will not be synced for that song.
key | optional | type | default | description |
---|---|---|---|---|
module |
False | string | The module name of the app. Must be spotify_mood_lights_sync . |
|
class |
False | string | The name of the Class. Must be SpotifyMoodLightsSync . |
|
client_id |
False | string | The client id of the Spotify-For-Developers app to use for accessing the Spotify API. | |
client_secret |
False | string | The client secret of the Spotify-For-Developers app to use for accessing the Spotify API. | |
media_player |
False | string | The entity_id of the media player to sync from. | |
light |
False | string | The entity_id of the light or light group to sync. | |
color_profile |
True | string | default |
The color profile to use for mapping moods to colors. Possible values are default , saturated , or custom . When custom is specified, the color map will be built from the parameters in custom_profile . |
mode |
True | string | direct |
Possible values are direct or search . Use search if you want to use a non-spotify media_player . Use direct when using a spotify media_player . |
max_retries |
True | number | 1 |
Number of times a Spotify API call should be retried after a connection error before the track is skipped. |
custom_profile |
True | object | Parameters to use for the custom color_profile . See Custom color profile section. |
|
custom_profile.color_mode |
False | string | Possible values are 'rgb' or 'hs'. See Custom color profile section. |
|
custom_profile.global_weight |
True | number | 1 |
Used in 'rgb' mode. Weight applied to all sampling points. See Custom color profile section. |
custom_profile.sample_data |
False | object | Used in 'rgb' mode. Sample data consisting of point-color pairs. See Custom color profile section. |
|
custom_profile.sample_data.point |
False | tuple | Used in 'rgb' mode. A point in the [0, 1]X[0, 1] range. See Custom color profile section. |
|
custom_profile.sample_data.color |
False | tuple | Used in 'rgb' mode. An RGB color value in the [0,255] range for each channel. See Custom color profile section. |
|
custom_profile.sample_data.local_weight |
True | number | 1 |
Used in 'rgb' mode. Weight applied to the sample point. See Custom color profile section. |
custom_profile.mirror_x |
True | boolean | False |
Used in 'hs' mode. Mirrors the hue angle in the x direction. See Custom color profile section. |
custom_profile.mirror_y |
True | boolean | False |
Used in 'hs' mode. Mirrors the hue angle in the y direction. See Custom color profile section. |
custom_profile.rotation |
True | number | 0 |
Used in 'hs' mode. Rotates the hue angle. See Custom color profile section. |
custom_profile.drop_off |
True | number | 1 |
Used in 'hs' mode. How fast the saturation drops off towards the center (0 for no saturation loss). See Custom color profile section. |
color_map_image |
True | object | Output the color map as an image for debugging. | |
color_map_image.size |
False | number | Size (height=width) of the output image in pixels. | |
color_map_image.location |
False | string | Path to which the image should be saved. |
You can create your own color profile for the app to use by specifying the custom_profile
app argument and
setting color_profile
to custom
.
The mood of a song is a 2-dimensional value in the range [0.0,1.0]
x[0.0,1.0]
where the first axis is
the valence, and the second axis the energy of the song. In general, the color value for a song is then sampled from a
color field based on where the mood value of that song lies on the 2D plane. See the Spotify API for more
information on these values.
Color profiles use either the RGB or the HS color space with different methods for sampling colors, respectively. While
RGB profiles perform an IDW interpolation, HS profiles simply map the positional information to a color circle.
Therefore, the custom_profile
profiles takes a different set of parameters depending on which option is given for
custom_profile.color_mode
.
In order to create an RGB color map the app expects a list of 2D sample points with a corresponding RGB color for each point.
For a given point on the mood plane, the color is then interpolated between the given sample points.
To give individual samples more weight you can add the custom_profile.sample_data.local_weight
option to any point-color pair.
Additionally, the custom_profile.global_weight
option gets applied to all points.
A higher weight value effectively increases the influence radius of a color sample.
For reference, the following section replicates the default profile:
spotify_mood_lights_sync:
color_profile: custom
custom_profile:
'color_mode': rgb
'global_weight': 2
'sample_data':
- 'point': [0.0, 0.5]
'color': [128, 0, 128]
'local_weight': 1
- 'point': [0.0, 1.0]
'color': [255, 0, 0]
'local_weight': 1
- 'point': [0.5, 1.0]
'color': [255, 165, 0]
'local_weight': 1
- 'point': [1.0, 1.0]
'color': [255, 255, 0]
'local_weight': 1
- 'point': [1.0, 0.0]
'color': [0, 205, 0]
'local_weight': 1
- 'point': [0.5, 0.0]
'color': [0, 180, 255]
'local_weight': 1
- 'point': [0.0, 0.0]
'color': [0, 0, 255]
'local_weight': 1
For HS profiles, the app calculates the angle and distance of the query point to the center of the mood plane. The angle gets mapped to a hue value while the distance maps to a saturation value. The origin for the hue angle is the center-right of the mood plane. This hue mapping can be mirrored and rotated. A drop-off factor is applied to the saturation to modify the saturation curve, where a factor of 0 preserves full saturation for the whole color map. For reference, the following section replicates the saturated profile:
spotify_mood_lights_sync:
color_profile: custom
custom_profile:
color_mode': hs
mirror_x: True
mirror_y: False
rotation: -60
drop_off: 0
If you wish to view the color map currently in use, e.g. for debugging custom color profiles, you additionally need the following packages. These are, however, not needed for standard app operation:
python_packages:
- Pillow
system_packages:
- py3-pillow
Adding the color_map_image
key in the config will prompt the app to generate an image file of the used color
map, where the x and y axes map to valence and energy, respectively. You can specify the pixel size, i.e. height and
width, of the image and the location to which it should be saved.
spotify_mood_lights_sync:
color_map_image:
size: 50
location: /config/www/spotify-lights-sync/test.png
This project is based on the following projects: