125 lines
6.1 KiB
Python
125 lines
6.1 KiB
Python
import time
|
|
from PIL import Image, ImageFont, ImageDraw
|
|
from ST7789 import ST7789
|
|
from glob import glob
|
|
import struct
|
|
import smbus
|
|
import sys
|
|
import musicpd
|
|
from math import floor
|
|
|
|
class SoundslabDisplay:
|
|
def __init__(self, player_client):
|
|
self.screen_size = 240, 240
|
|
self.spi_speed_mhz = 80
|
|
self.st7789 = ST7789(
|
|
rotation=90,
|
|
port=0,
|
|
cs=1,
|
|
dc=9,
|
|
backlight=13,
|
|
spi_speed_hz=self.spi_speed_mhz * 1000 * 1000
|
|
)
|
|
self.current_background = Image.new("RGBA", self.screen_size, (0, 0, 255, 255))
|
|
self.current_overlay = Image.new("RGBA", self.screen_size, (0, 0, 0, 0))
|
|
self.current_menu = Image.new("RGBA", self.screen_size, (0, 0, 0, 0))
|
|
self.fg_color = (255, 255, 255, 211)
|
|
self.bg_color = (0, 0, 0, 127)
|
|
|
|
# the connection to mpd passed in
|
|
self.player_client = player_client
|
|
|
|
# track battery voltage over time so we can figure out if we're charging the battery or not
|
|
self.previous_voltage = 0.0
|
|
# track currently playing song's art path to eliminate unnecessary reloads of the same image file
|
|
self.current_art_path = None
|
|
|
|
def getBatteryState(self):
|
|
bus = smbus.SMBus(1)
|
|
|
|
address = 0x36
|
|
|
|
read = bus.read_word_data(address, 2)
|
|
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
|
voltage = swapped * 78.125 / 1000000
|
|
|
|
read = bus.read_word_data(address, 4)
|
|
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
|
capacity = swapped / 256
|
|
|
|
self.previous_voltage = voltage
|
|
|
|
return (voltage, capacity)
|
|
|
|
|
|
def updateOverlay(self):
|
|
# initialize overlay
|
|
im_overlay = Image.new("RGBA", self.screen_size, (0, 0, 0, 0))
|
|
font = ImageFont.truetype(font='/usr/share/fonts/truetype/hack/Hack-Bold.ttf', size=18)
|
|
small_font = ImageFont.truetype(font='/usr/share/fonts/truetype/hack/Hack-Regular.ttf', size=14)
|
|
overlay = ImageDraw.Draw(im_overlay)
|
|
|
|
# draw four rects on edges of screen_size
|
|
overlay.rectangle([(0, 0), (self.screen_size[0], 20)], self.bg_color) # top bar
|
|
overlay.rectangle([(0, self.screen_size[1] - 20), (self.screen_size[0], self.screen_size[1])], self.bg_color) # bottom bar
|
|
overlay.rectangle([(0, 20), (20, self.screen_size[1] - 20)], self.bg_color) # left bar
|
|
overlay.rectangle([(self.screen_size[0] - 20, 20), (self.screen_size[0], self.screen_size[1] - 20)], self.bg_color) # right bar
|
|
|
|
# get status from mpd
|
|
current_status = self.player_client.status()
|
|
current_track_number = int(current_status['song']) + 1
|
|
total_track_number = current_status['playlistlength']
|
|
track_progress_percent = float(current_status['elapsed']) / float(current_status['duration'])
|
|
print("track progress:" + str(track_progress_percent))
|
|
# add track # / total #
|
|
track_and_queue = str(current_track_number) + " of " + str(total_track_number)
|
|
overlay.text((10, 0), track_and_queue, font=font, fill=self.fg_color)
|
|
|
|
# add battery level
|
|
previous_voltage = self.previous_voltage
|
|
(voltage, capacity) = self.getBatteryState()
|
|
battery_display = '{:02.2f}'.format(capacity) + '%'
|
|
battery_display_offset = 80
|
|
print("Battery: voltage: " + str(voltage) + " prev voltage: " + str(previous_voltage) + " capacity: " + str(capacity))
|
|
if voltage > previous_voltage:
|
|
# we're probably charging!
|
|
battery_display = 'Chrg ' + battery_display
|
|
battery_display_offset = 130
|
|
overlay.text((self.screen_size[0] - battery_display_offset, 0), battery_display, font=font, fill=self.fg_color)
|
|
|
|
# add progress meter
|
|
overlay.rectangle([(70, self.screen_size[1] - 15), (self.screen_size[0] - 70, self.screen_size[1] - 5)], fill=(0, 0, 0, 0), outline=self.fg_color, width=1)
|
|
overlay.rectangle([(70, self.screen_size[1] - 15), (int((self.screen_size[0] - 140) * track_progress_percent) + 70, self.screen_size[1] - 5)], fill=self.fg_color, outline=self.fg_color, width=1)
|
|
|
|
# add playhead position and song duration displays at beginning and end of progress meter
|
|
(time_width, time_height) = overlay.textsize(text='00:00', font=small_font)
|
|
playhead = str(floor(float(current_status['elapsed']) / 60)) + ":" + "{:02d}".format(floor(float(current_status['elapsed']) % 60))
|
|
duration = str(floor(float(current_status['duration']) / 60)) + ":" + "{:02d}".format(floor(float(current_status['duration']) % 60))
|
|
overlay.text((5, self.screen_size[1] - 20 + floor(time_height / 2)), playhead, font=small_font, fill=self.fg_color)
|
|
overlay.text((self.screen_size[0] - 5 - time_width, self.screen_size[1] - 20 + floor(time_height / 2)), duration, font=small_font, fill=self.fg_color)
|
|
|
|
self.current_overlay = im_overlay.copy()
|
|
|
|
def updateAlbumArt(self):
|
|
current_status = self.player_client.status()
|
|
song_data = self.player_client.playlistid(current_status['songid'])
|
|
path_info = song_data[0]['file'].split('/')
|
|
cover_image_file = '/media/usb0/' + path_info[0] + '/' + path_info[1] + '/cover.jpg'
|
|
if cover_image_file != self.current_art_path:
|
|
self.current_art_path = cover_image_file
|
|
im = Image.open(cover_image_file).convert("RGBA")
|
|
image = im.resize((200, 200))
|
|
# get dominant color from album art
|
|
#test_image = im.convert("RGB")
|
|
#test_image.resize((1, 1), resample=0)
|
|
#dominant_color = test_image.getpixel((0, 0))
|
|
# get top left pixel color instead and use that!
|
|
dominant_color = image.getpixel((0, 0))
|
|
backing = Image.new("RGBA", self.screen_size, dominant_color)
|
|
backing.paste(image, (20, 20))
|
|
self.current_background = backing.copy()
|
|
|
|
def updateDisplay(self):
|
|
tempoutput = Image.alpha_composite(self.current_background, self.current_overlay)
|
|
self.st7789.display(Image.alpha_composite(tempoutput, self.current_menu))
|