Use SIGINT to end script, systemd service. Use static/dynamic UI
This commit is contained in:
parent
c0c0d4053a
commit
99bc13c8bb
85
mpdlisten.py
85
mpdlisten.py
|
@ -6,6 +6,7 @@
|
|||
import musicpd
|
||||
from math import floor
|
||||
from os import environ
|
||||
import signal
|
||||
import sys
|
||||
from time import sleep
|
||||
# Relay
|
||||
|
@ -14,11 +15,12 @@ import RPi.GPIO as GPIO
|
|||
from luma.core.interface.serial import i2c
|
||||
from luma.core.render import canvas
|
||||
from luma.oled.device import ssd1306
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
# MPD config
|
||||
off_delay = 3
|
||||
mpd_host='localhost'
|
||||
mpd_port=6600
|
||||
mpd_host=None
|
||||
mpd_port=None
|
||||
mpd_passwd = None
|
||||
mpd_states = ['play', 'pause', 'stop', 'unknown']
|
||||
|
||||
|
@ -31,6 +33,9 @@ GPIO.setup(RELAIS_1_GPIO, GPIO.OUT) # GPIO Assign mode
|
|||
serial = i2c(port=1, address=0x3C)
|
||||
device = ssd1306(serial)
|
||||
|
||||
# GUI config
|
||||
number_of_btn = 4
|
||||
|
||||
# TODO: get ctrlc state
|
||||
ctrlc_pressed = False
|
||||
|
||||
|
@ -80,24 +85,59 @@ if 'MPD_HOST' in environ:
|
|||
if 'MPD_PORT' in environ:
|
||||
mpd_port = environ['MPD_PORT']
|
||||
|
||||
static_ui = None
|
||||
menu_mode = "playback"
|
||||
|
||||
|
||||
def sectomin(sec:str):
|
||||
minute = 0
|
||||
minute = floor(float(sec)/60)
|
||||
second = round(float(sec)-minute*60)
|
||||
return "{}:{}".format(str(minute), str(second))
|
||||
|
||||
|
||||
def generate_static_ui(mode:str):
|
||||
# ~ if mode == "playback":
|
||||
btn_width = floor((device.width-3) / 4)
|
||||
btn_height = 8
|
||||
menu_line_width = 1
|
||||
menu_bar_y = device.height - btn_height - menu_line_width
|
||||
|
||||
im = Image.new(mode='1', size=(device.width, device.height))
|
||||
draw = ImageDraw.Draw(im)
|
||||
# TODO: draw static UI only once as a PIL image
|
||||
draw.rectangle(device.bounding_box, outline="white", fill="black")
|
||||
draw.line([(0, menu_bar_y),(device.width, menu_bar_y)], width=menu_line_width)
|
||||
# TODO : use loop
|
||||
i = 1
|
||||
while i < number_of_btn:
|
||||
draw.line([((btn_width+1)*i, menu_bar_y),((btn_width+1)*i, device.height)], width=menu_line_width, fill="white")
|
||||
i+=1
|
||||
# Draw icons
|
||||
draw.regular_polygon(bounding_circle=(((btn_width+1)*0.5), (menu_bar_y + btn_height / 2), 3), n_sides=3, rotation=90, fill="white")
|
||||
draw.regular_polygon(bounding_circle=(((btn_width+1)*1.5), (menu_bar_y + btn_height / 2), 3), n_sides=3, rotation=270, fill="white")
|
||||
draw.regular_polygon(bounding_circle=(((btn_width+1)*2.5), (menu_bar_y + btn_height / 2), 3), n_sides=4, rotation=0, fill="white")
|
||||
draw.regular_polygon(bounding_circle=(((btn_width+1)*3.5), (menu_bar_y + btn_height / 2), 3), n_sides=3, rotation=180, fill="white")
|
||||
|
||||
return im
|
||||
|
||||
|
||||
def update_display(device, currentsong, status):
|
||||
# ~ print(currentsong['artist'])
|
||||
# ~ print(currentsong['title'])
|
||||
# ~ print(status['time'])
|
||||
# ~ print("{}/{}".format(status['time'], sectomin(status['duration'])))
|
||||
with canvas(device) as draw:
|
||||
draw.rectangle(device.bounding_box, outline="white", fill="black")
|
||||
draw.text((10, 5), currentsong['artist'], fill="white")
|
||||
draw.text((10, 18), currentsong['title'], fill="white")
|
||||
draw.text((10, 31), currentsong['album'], fill="white")
|
||||
draw.text((10, 44), "{}/{}".format(status['time'], sectomin(status['duration'])), fill="white")
|
||||
draw.regular_polygon(bounding_circle=(14, 55, 8), n_sides=3, rotate=90, fill="white")
|
||||
# We want to display 4 buttons at the bottom of the screen
|
||||
btn_width = floor((device.width-3) / 4)
|
||||
btn_height = 8
|
||||
menu_line_width = 1
|
||||
menu_bar_y = device.height - btn_height - menu_line_width
|
||||
# Draw dynamic UI
|
||||
ui = static_ui
|
||||
draw = ImageDraw.Draw(ui)
|
||||
draw.text((10, 2), currentsong['artist'], fill="white")
|
||||
draw.text((10, 14), currentsong['title'], fill="white")
|
||||
draw.text((10, 26), currentsong['album'], fill="white")
|
||||
if 'elapsed' in status:
|
||||
draw.text((10, 38), "{}/{}".format(sectomin(status['elapsed']), sectomin(status['duration'])), fill="white")
|
||||
device.display(ui)
|
||||
|
||||
|
||||
def main(args):
|
||||
previous_sond_id = None
|
||||
|
@ -107,8 +147,10 @@ def main(args):
|
|||
client = musicpd.MPDClient()
|
||||
if mpd_passwd is not None:
|
||||
client.pwd = mpd_passwd
|
||||
client.host = mpd_host
|
||||
client.port = mpd_port
|
||||
if mpd_host is not None:
|
||||
client.host = mpd_host
|
||||
if mpd_port is not None:
|
||||
client.port = mpd_port
|
||||
client.mpd_timeout = 5
|
||||
try:
|
||||
client.connect()
|
||||
|
@ -117,6 +159,8 @@ def main(args):
|
|||
print("Check host and port are correct.")
|
||||
# ~ print(client.status()) # duration, elapsed, volume, repeat, random, single
|
||||
# ~ print(client.currentsong()) # artist, title, album
|
||||
global static_ui
|
||||
static_ui = generate_static_ui(menu_mode)
|
||||
while ctrlc_pressed is False:
|
||||
mpd_status = client.status()
|
||||
if len(mpd_status):
|
||||
|
@ -149,9 +193,18 @@ def main(args):
|
|||
previous_state = play_state
|
||||
sleep(1)
|
||||
update_display(device, mpd_client_currentsong, mpd_client_status)
|
||||
device.cleanup()
|
||||
client.disconnect()
|
||||
return 0
|
||||
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
global ctrlc_pressed
|
||||
print('You pressed Ctrl+C!')
|
||||
ctrlc_pressed = True
|
||||
# ~ sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Mpd listen python script
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/home/music/mpdlisten
|
||||
ExecStart=/home/music/mpdlisten/mpdlisten.py
|
||||
KillSignal=SIGINT
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
Loading…
Reference in New Issue