PirateAudio/tft_moode_coverart.py

265 lines
8.8 KiB
Python

#!/usr/bin/env python
import time
from colorsys import hsv_to_rgb
from PIL import ImageFont, Image, ImageDraw, ImageStat
import os
import os.path
from os import path
import ST7789 as ST7789
from socketIO_client import SocketIO, LoggingNamespace
import requests
from io import BytesIO
from numpy import mean
import sys
import logging
# logging.getLogger('socketIO-client').setLevel(logging.DEBUG)
# logging.basicConfig()
import signal
import RPi.GPIO as GPIO
# get the path of the script
# script_path = os.path.dirname(os.path.abspath( __file__ ))
script_path = os.path.dirname(os.path.abspath(__file__))
# set script path as current directory
os.chdir(script_path)
def on_connect():
print("connect")
def on_disconnect():
print("disconnect")
img = Image.new("RGBA", (240, 240), color=(0, 0, 0, 25))
img = Image.open("/volumio/app/plugins/miscellanea/albumart/default.jpg")
img = img.resize((WIDTH, HEIGHT))
draw = ImageDraw.Draw(img, "RGBA")
draw.text((10, 200), "shuting down ...", font=font_m, fill=(255, 255, 255))
disp.display(img)
def on_push_state(*args):
img = Image.new("RGBA", (240, 240), color=(0, 0, 0, 25))
global status
global service
status = args[0]["status"]
service = args[0]["service"]
# Load albumcover or radio cover
albumart = args[0]["albumart"]
if len(albumart) == 0: # to catch a empty field on start
albumart = "http://localhost:3000/albumart"
if "http:" not in albumart:
albumart = "http://localhost:3000" + args[0]["albumart"]
print(albumart)
response = requests.get(albumart)
img = Image.open(BytesIO(response.content))
img = img.resize((WIDTH, HEIGHT))
# Light / Dark Symbols an bars, depending on background
im_stat = ImageStat.Stat(img)
im_mean = im_stat.mean
mn = mean(im_mean)
txt_col = (255, 255, 255)
# bar_col = (255, 255, 255, 255)
bar_bgcol = (200, 200, 200)
bar_col = (255, 255, 255)
dark = False
if mn > 175:
txt_col = (55, 55, 55)
dark = True
# bar_col = (100, 100, 100, 225)
bar_bgcol = (255, 255, 255)
bar_col = (100, 100, 100)
if mn < 80:
txt_col = (200, 200, 200)
# paste button symbol overlay in light/dark mode
if status == "play":
if dark is False:
img.paste(pause_icons, (0, 0), pause_icons)
else:
img.paste(pause_icons_dark, (0, 0), pause_icons_dark)
else:
if dark is False:
img.paste(play_icons, (0, 0), play_icons)
else:
img.paste(play_icons_dark, (0, 0), play_icons_dark)
draw = ImageDraw.Draw(img, "RGBA")
top = 7
if "artist" in args[0]:
x1 = 20
w1, y1 = draw.textsize(args[0]["artist"], font_m)
x1 = x1 - 20
if x1 < (WIDTH - w1 - 20):
x1 = 0
if w1 <= WIDTH:
x1 = (WIDTH - w1) // 2
draw.text((x1, top), args[0]["artist"], font=font_m, fill=txt_col)
top = 35
if "album" in args[0]:
if args[0]["album"] is not None:
x2 = 20
w2, y2 = draw.textsize(args[0]["album"], font_s)
x2 = x2 - 20
if x2 < (WIDTH - w2 - 20):
x2 = 0
if w2 <= WIDTH:
x2 = (WIDTH - w2) // 2
draw.text((x2, top), args[0]["album"], font=font_s, fill=txt_col)
if "title" in args[0]:
x3 = 20
w3, y3 = draw.textsize(args[0]["title"], font_l)
x3 = x3 - 20
if x3 < (WIDTH - w3 - 20):
x3 = 0
if w3 <= WIDTH:
x3 = (WIDTH - w3) // 2
# thin border
# shadowcolor = "black"
# draw.text((x3-1, 105), args[0]['title'], font=font_l,
# fill=shadowcolor)
# draw.text((x3+1, 105), args[0]['title'], font=font_l,
# fill=shadowcolor)
# draw.text((x3, 105-1), args[0]['title'], font=font_l,
# fill=shadowcolor)
# draw.text((x3, 105+1), args[0]['title'], font=font_l,
# fill=shadowcolor)
draw.text(
(x3, 105), args[0]["title"], font=font_l, fill=txt_col
) # fill by mean
# volume bar
vol_x = int((float(args[0]["volume"]) / 100) * (WIDTH - 33))
# draw.rectangle((5, 184, WIDTH-34, 184+8), (255, 255, 255, 145))
draw.rectangle((5, 184, WIDTH - 34, 184 + 8), bar_bgcol) # background
draw.rectangle((5, 184, vol_x, 184 + 8), bar_col)
# time bar
if "duration" in args[0]:
duration = args[0]["duration"] # seconds
if duration != 0:
if "seek" in args[0]:
seek = args[0]["seek"] # time elapsed seconds
print("seek: ", seek)
if seek != 0 and seek is not None:
el_time = int(float(seek) / 1000)
du_time = int(float(args[0]["duration"]))
dur_x = int((float(el_time) / float(du_time)) * (WIDTH - 10))
# draw.rectangle((5, 222, WIDTH-5, 222 + 12), (255, 255, 255, 145))
draw.rectangle(
(5, 222, WIDTH - 5, 222 + 12), bar_bgcol
) # background
draw.rectangle((5, 222, dur_x, 222 + 12), bar_col)
# Draw the image on the display hardware
disp.display(img)
socketIO = SocketIO("localhost", 3000)
socketIO.on("connect", on_connect)
# Create ST7789 LCD display class.
disp = ST7789.ST7789(
rotation=90, # Needed to display the right way up on Pirate Audio
port=0, # SPI port
cs=1, # SPI port Chip-select channel
dc=9, # BCM pin used for data/command
backlight=13,
spi_speed_hz=80 * 1000 * 1000,
)
# Initialize display.
disp.begin()
WIDTH = 240
HEIGHT = 240
font_s = ImageFont.truetype(script_path + "/fonts/Roboto-Medium.ttf", 20)
font_m = ImageFont.truetype(script_path + "/fonts/Roboto-Medium.ttf", 24)
font_l = ImageFont.truetype(script_path + "/fonts/Roboto-Medium.ttf", 30)
play_icons = Image.open("images/controls-play.png").resize((240, 240))
play_icons_dark = Image.open("images/controls-play-dark.png").resize((240, 240))
pause_icons = Image.open("images/controls-pause.png").resize((240, 240))
pause_icons_dark = Image.open("images/controls-pause-dark.png").resize((240, 240))
# vol_icons = Image.open(script_path + '/images/controls-vol.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# vol_icons_dark = Image.open(script_path + '/images/controls-vol-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# bt_back = Image.open(script_path + '/images/bta.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# ap_back = Image.open(script_path + '/images/airplay.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# jp_back = Image.open(script_path + '/images/jack.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sp_back = Image.open(script_path + '/images/spotify.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sq_back = Image.open(script_path + '/images/squeeze.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
BUTTONS = [5, 6, 16, 20]
# BUTTONS = [16]
LABELS = ["A", "B", "X", "Y"]
# Set up RPi.GPIO with the "BCM" numbering scheme
GPIO.setmode(GPIO.BCM)
# Buttons connect to ground when pressed, so we should set them up
# with a "PULL UP", which weakly pulls the input signal to 3.3V.
GPIO.setup(BUTTONS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def handle_button(pin):
label = LABELS[BUTTONS.index(pin)]
print("Button press detected on pin: {} label: {}".format(pin, label))
if pin == 5:
# print('Play/pause')
print(status, service)
if (status == "play") and (service == "webradio"):
print("stop - webradio")
socketIO.emit("stop")
elif status == "play":
print("pause")
socketIO.emit("pause")
else:
print("play")
socketIO.emit("play")
if pin == 6:
print("volDown")
socketIO.emit("volume", "-")
if pin == 16:
print("Next")
socketIO.emit("next")
if pin == 20:
print("volUp")
socketIO.emit("volume", "+")
def main():
while True:
print("In main")
for pin in BUTTONS:
GPIO.add_event_detect(pin, GPIO.FALLING, handle_button, bouncetime=100)
disp.set_backlight(True)
# mit socket verbinden
socketIO.on("pushState", on_push_state)
# get initial state
socketIO.emit("getState", "", on_push_state)
socketIO.wait()
# socketIO.wait_for_callbacks(seconds=1)
# time.sleep(1)
time.sleep(0.01)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
img = Image.new("RGB", (240, 240), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
draw.rectangle((0, 0, 240, 240), (0, 0, 0))
disp.display(img)
disp.set_backlight(False)
pass