DEV Community

Cover image for Spotify Desk Widget with a Raspberry Pi and e-Paper Display
Enrique Flores
Enrique Flores

Posted on

4 1

Spotify Desk Widget with a Raspberry Pi and e-Paper Display

I’ve been looking for a fun coding project to work on my free time so I remembered I had a 2.7 Inch e-Paper display laying around and decided to finally put it to use. As someone who listens to music on Spotify all day, I found myself constantly opening the app to check the current title and artist of the songs I liked. This is when I had the very original idea of making a Spotify e-Paper desk widget thing.

To build this project I used a local Home Assistant that I have running in another Pi. The automation gets triggered whenever a new song is played, which then fires a webhook to my Raspberry Pi 4. The webhook executes a Python script that retrieves the current song information from Home Assistant's API then using Python PIL library we can create the template with the album cover and finally we render it on the e-Paper display.

Here’s a overall general guide on how you can build this:

  • Set up a Raspberry Pi with the Waveshare e-Paper display.
  • Install and configure a local Home Assistant instance.
  • Create a Spotify developer account and register a new app to obtain the necessary API keys.
  • Configure the Spotify integration in your Home Assistant.
  • Create a Home Assistant automation script that triggers a RESTful command whenever a new song is played on Spotify.

Register RESTful command as a service in Home Assistant's configuration file:

rest_command:
 spotify_epaper:
 url: "http://YOURLOCAL_RASPBERRYPI/hooks/spotify-e-paper-webhook"
 verify_ssl: false
 method: GET
Enter fullscreen mode Exit fullscreen mode

The Home Assistant automation script is very simple:

alias: Spotify ePaper Automation
description: ""
trigger:
 — platform: state
 entity_id:
 — media_player.spotify
 attribute: media_title
condition: []
action:
 — service: rest_command.spotify_epaper
 data: {}
mode: single
Enter fullscreen mode Exit fullscreen mode
  • I created the webhook endpoint on the Raspberry Pi using https://github.com/adnanh/webhook

  • When the webhook is triggered a Python script is executed and this is where the magic happens.

This Python script initializes the e-paper display with epd2in7.EPD() (epd2in7 is provided by Waveshare). The fonts are loaded and a new image is created using Image.new(). The ImageDraw.Draw() method is used to create a rectangle and text.

The script then sends requests to the local Home Assistant instance using the requests library to retrieve weather and Spotify information. The data is then processed and pasted onto the image using draw.text() and draw.multiline_text().

Finally, the image is displayed on the e-Paper with epd.display() and the display is put to sleep to save power with epd.sleep().

#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

import logging
from waveshare_epd import epd2in7
import time
from PIL import Image, ImageDraw, ImageFont
import traceback
import requests, json
from datetime import date

today = date.today()
logging.basicConfig(level=logging.DEBUG)

try:
    logging.info("Start...")

    epd = epd2in7.EPD()
    logging.info("Init and Clear")
    epd.init()
    epd.Clear(0xFF)

    font15 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15)
    font20 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20)
    font25 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 25)

    # Create the image
    logging.info("Create the image...")
    image = Image.new('1', (epd.height, epd.width), 255)
    draw = ImageDraw.Draw(image)
    draw.rectangle([(121,0),(270,119)],fill = 0)

    weather_url = "http://HOME_ASSISTANT_LOCAL:8123/api/states/weather.forecast_home"
    weather_headers = {
        "Authorization": "Bearer TOKEN",
        "content-type": "application/json",
    }

    weather_response = requests.get(weather_url, headers=weather_headers)

    if weather_response.status_code == 200:
        print('Connection to Weather successful.')
        # get data in json format
        data = weather_response.json()

        attributes = data['attributes']
        state = data['state']

        temperature = attributes['temperature']
        temperature_unit = attributes['temperature_unit']

        # Set strings to be printed to screen
        date = today.strftime("%A %d")
        draw.multiline_text((130, 60), str(temperature) + temperature_unit + "\n" + date, font=font25, fill= 1)

    spotify_url = "http://HOME_ASSISTANT_LOCAL:8123/api/states/media_player.spotify"
    spotify_headers = {
        "Authorization": "Bearer TOKEN",
        "content-type": "application/json",
    }

    spotify_response = requests.get(spotify_url, headers=spotify_headers)

    if spotify_response.status_code == 200:
        print('Connection to Spotify successful.')
        # get data in json format
        data = spotify_response.json()

        attributes = data['attributes']
        media_title = attributes['media_title']
        media_artist = attributes['media_artist']
        entity_picture = attributes['entity_picture']

        # get album cover and save it as png file
        img_url = 'http://HOME_ASSISTANT_LOCAL:8123' + entity_picture
        path = os.path.join(picdir, 'album_cover.png')
        response = requests.get(img_url)
        if response.status_code == 200:
            with open(path, 'wb') as f:
                f.write(response.content)

        # Open album image, resize and paste 
        album_cover = Image.open(os.path.join(picdir, 'album_cover.png'))
        album_cover.thumbnail((120, 120), reducing_gap=2.0)
        image.paste(album_cover, (0,0))  

        # Set strings to be printed to screen
        draw.text((5, 120), media_title, font = font25, fill = 0)
        draw.text((5, 150), media_artist, font = font15, fill = 0)


    epd.display(epd.getbuffer(image))

    logging.info("Go to sleep and save power...")
    epd.sleep()

except IOError as e:
    logging.info(e)

except KeyboardInterrupt:    
    logging.info("ctrl + c:")
    epd2in7.epdconfig.module_exit()
    exit()
Enter fullscreen mode Exit fullscreen mode

Image description

This project was a lot of fun and super easy to achieve. I love how I made it work with my already running Home Assistant setup, this will let me integrate the e-Paper display even further with other automations.

With just a few simple steps, I was able to create a cool geeky gadget to display on my desk. The combination of Home Assistant’s powerful integrations, the Raspberry Pi’s versatility, and Waveshare's e-Paper display made this project a breeze to build.

My next iteration will include:

  • Send all the necessary data in the webhook payload itself to avoid all those requests in the Python script
  • Resize and filter the album cover with better algorithms for black and white display
  • Add upcoming work calendar events
  • Utilize those fours button keys in the display
  • Upload code to Github (I need to clean the code first and setup the appropriate env vars)

If you’re looking for a fun coding project to work on, I highly recommend giving this one a try!

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (1)

Collapse
 
wiiliam_903656da78bced7bb profile image
Wiiliam

This is such a creative project! Integrating a Raspberry Pi with an e-Paper display to show real-time Spotify info is a brilliant idea, especially for those who love automation. It’s impressive how Home Assistant plays a key role in making everything seamless. If you're looking to enhance your Spotify experience even further, you can Get Now a version that unlocks premium features like ad-free listening, unlimited skips, and high-quality audio. Looking forward to seeing how your next iteration turns out!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay