dot3k/mpd_dot3k.py

207 lines
5.8 KiB
Python
Raw Normal View History

2017-03-12 17:04:43 +01:00
#!/usr/bin/env python3
2017-03-12 22:38:17 +01:00
# Author: raspbeguy <raspbeguy@hashtagueule.fr>
# 2017-03-12
# License: MIT
2017-03-12 17:04:43 +01:00
import queue
import threading
2017-03-12 22:38:17 +01:00
import signal
import sys
2017-03-15 22:40:25 +01:00
import os
import audioop
2017-03-12 17:04:43 +01:00
import dot3k.lcd as lcd
2017-03-12 22:38:17 +01:00
import dot3k.backlight as backlight
import dot3k.joystick as nav
2017-03-12 17:04:43 +01:00
from mpd import MPDClient
2017-03-12 17:57:56 +01:00
rotate_pause = 10 # delay in rotation steps
2017-03-12 17:04:43 +01:00
char_play = [
0b10000,
0b11000,
0b11100,
0b11110,
0b11110,
0b11100,
0b11000,
0b10000,
]
char_pause = [
0b00000,
0b11011,
0b11011,
0b11011,
0b11011,
0b11011,
0b11011,
0b00000,
]
char_stop = [
0b00000,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
]
q = queue.Queue()
2017-03-15 22:40:25 +01:00
def vumeter():
fifo = os.open('/tmp/mpd.fifo', os.O_RDONLY)
while run_event.is_set():
try:
rawStream = os.read(fifo, 4096)
except OSError as err:
if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
rawStream = None
else:
raise
if rawStream:
backlight.set_graph(audioop.rms(rawStream,2)/32768)
backlight.set_graph(0)
2017-03-12 17:04:43 +01:00
def stringrotate(text, width, step):
if len(text) > width:
fulltext = text + " - "
fulltext = fulltext[step:] + fulltext[:step]
return fulltext[:width]
else:
return text
def display():
title = ''
artist = ''
album = ''
song_file = '' # Useful to determine if current song actually changed
step_title = step_artist = step_album = 0
2017-03-12 22:38:17 +01:00
while run_event.is_set():
2017-03-12 17:04:43 +01:00
try:
2017-03-12 17:57:56 +01:00
arg = q.get(timeout=0.2)
2017-03-12 17:04:43 +01:00
status = arg['status']['state']
if status == "play":
2017-03-15 22:40:25 +01:00
backlight.rgb(0, 0, 255) # green
2017-03-12 17:04:43 +01:00
lcd.create_char(0, char_play)
elif status == "pause":
2017-03-15 22:40:25 +01:00
backlight.rgb(0, 255, 0) # blue
2017-03-12 17:04:43 +01:00
lcd.create_char(0, char_pause)
else:
2017-03-15 22:40:25 +01:00
backlight.rgb(255, 0, 0)
2017-03-12 17:04:43 +01:00
lcd.create_char(0, char_stop)
2017-03-12 22:38:17 +01:00
if status not in {'play','pause'} or song_file != arg['song']['file']:
song_file = arg['song']['file'] if 'file' in arg['song'].keys() else ''
title = arg['song']['title'] if 'title' in arg['song'].keys() else ''
artist = arg['song']['artist'] if 'artist' in arg['song'].keys() else ''
album = arg['song']['album'] if 'album' in arg['song'].keys() else ''
2017-03-12 17:04:43 +01:00
lcd.clear()
lcd.set_cursor_position(0, 0)
lcd.write(chr(0))
2017-03-12 22:38:17 +01:00
step_title = step_artist = step_album = 0
delay_title = delay_artist = delay_album = rotate_pause
2017-03-12 17:04:43 +01:00
if len(title) <= 15:
lcd.set_cursor_position(1, 0)
lcd.write(title)
if len(artist) <= 16:
lcd.set_cursor_position(0, 1)
lcd.write(artist)
if len(album) <= 16:
lcd.set_cursor_position(0, 2)
lcd.write(album)
except queue.Empty:
2017-03-12 22:38:17 +01:00
if len(title) > 15:
if step_title == 0 and delay_title > 0:
delay_title -= 1
else:
step_title = (step_title + 1) % (len(title) + 3)
if delay_title == 0:
delay_title = rotate_pause
if len(artist) > 16:
if step_artist == 0 and delay_artist > 0:
delay_artist -= 1
else:
step_artist = (step_artist + 1) % (len(artist) + 3)
if delay_artist == 0:
delay_artist = rotate_pause
if len(album) > 16:
if step_album == 0 and delay_album > 0:
delay_album -= 1
else:
step_album = (step_album + 1) % (len(album) + 3)
if delay_album == 0:
delay_album = rotate_pause
2017-03-12 17:04:43 +01:00
if len(title) > 15:
lcd.set_cursor_position(1, 0)
lcd.write(stringrotate(title, 15, step_title))
if len(artist) > 16:
lcd.set_cursor_position(0, 1)
lcd.write(stringrotate(artist, 16, step_artist))
if len(album) > 16:
lcd.set_cursor_position(0, 2)
lcd.write(stringrotate(album, 16, step_album))
2017-03-12 22:38:17 +01:00
lcd.clear()
@nav.on(nav.BUTTON)
def button_center(pin):
client = MPDClient() # Please close your eyes
client.connect("localhost", 6600) # Dirty dirty dirty...
if client.status()['state'] in {'play','pause'}:
client.pause()
else:
client.play()
client.close() # Okay, you can open your eyes
@nav.on(nav.LEFT)
def button_left(pin):
client = MPDClient() # Please close your eyes
client.connect("localhost", 6600) # Dirty dirty dirty...
client.previous()
client.close() # Okay, you can open your eyes
@nav.on(nav.RIGHT)
def button_right(pin):
client = MPDClient() # Please close your eyes
client.connect("localhost", 6600) # Dirty dirty dirty...
client.next()
client.close() # Okay, you can open your eyes
def on_exit(sig, func=None):
run_event.clear()
t_display.join()
2017-03-15 22:40:25 +01:00
t_vumeter.join()
2017-03-12 22:38:17 +01:00
backlight.rgb(0, 0, 0)
backlight.rgb(0, 0, 0)
print("Screen sound be blank and light off now.")
sys.exit(0)
2017-03-15 22:40:25 +01:00
lcd.set_contrast(50)
2017-03-12 22:38:17 +01:00
run_event = threading.Event()
run_event.set()
2017-03-12 17:04:43 +01:00
client = MPDClient()
client.connect("localhost", 6600)
t_display = threading.Thread(name='display',target=display)
2017-03-15 22:40:25 +01:00
t_vumeter = threading.Thread(name='vumeter',target=vumeter)
2017-03-12 17:04:43 +01:00
t_display.start()
2017-03-15 22:40:25 +01:00
t_vumeter.start()
2017-03-12 17:04:43 +01:00
2017-03-12 22:38:17 +01:00
signal.signal(signal.SIGTERM, on_exit)
try:
while True:
q.put({'song': client.currentsong(), 'status' : client.status()})
client.idle('player')
except KeyboardInterrupt:
on_exit(None)