#!/usr/bin/env python3 # Author: raspbeguy # 2017-03-12 # License: MIT import queue import threading import signal import sys import os import audioop import dot3k.lcd as lcd import dot3k.backlight as backlight import dot3k.joystick as nav from mpd import MPDClient rotate_pause = 10 # delay in rotation steps 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() 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) 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 while run_event.is_set(): try: arg = q.get(timeout=0.2) status = arg['status']['state'] if status == "play": backlight.rgb(0, 0, 255) # green lcd.create_char(0, char_play) elif status == "pause": backlight.rgb(0, 255, 0) # blue lcd.create_char(0, char_pause) else: backlight.rgb(255, 0, 0) lcd.create_char(0, char_stop) 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 '' lcd.clear() lcd.set_cursor_position(0, 0) lcd.write(chr(0)) step_title = step_artist = step_album = 0 delay_title = delay_artist = delay_album = rotate_pause 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: 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 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)) 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() t_vumeter.join() backlight.rgb(0, 0, 0) backlight.rgb(0, 0, 0) print("Screen sound be blank and light off now.") sys.exit(0) lcd.set_contrast(50) run_event = threading.Event() run_event.set() client = MPDClient() client.connect("localhost", 6600) t_display = threading.Thread(name='display',target=display) t_vumeter = threading.Thread(name='vumeter',target=vumeter) t_display.start() t_vumeter.start() 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)