#!/usr/bin/python import serial import mpd import time import sys import logging logger = logging.getLogger() logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger.setLevel(logging.DEBUG) class Config: display_lines = 2 display_width = 16 display_length = display_lines * display_width class Daemon: line = "" playing = False def __init__(self): self.ser = serial.Serial(sys.argv[1], 9600, timeout=1) # raise timeout to let arduino start up self.ser.timeout = 15 incoming = self.readline() # arduino sometimes has a dirty buffer # and sends junk before the ready message if not incoming.endswith("ready"): sys.stderr.write("Got unexpected reply: "+incoming) raise Exception("Wrong client greeting") self.ser.timeout = 1 self.client = mpd.MPDClient() self.client.connect("localhost", 6600) logger.debug("connected") def readline(self): return self.ser.readline().decode("ascii").strip() def update(self): old_line = self.line old_playing = self.playing changed = False incoming = self.client.currentsong() self.line = incoming["artist"] + " - " + incoming["title"] if self.line != old_line: changed = True self.playing = self.client.status()["state"] == "play" if self.playing != old_playing: changed = True return changed def run(self): self.update() last_display_update = 0.0 last_song_update = 0.0 now = 0.0 time_diff = 0.0 current_position = 0 while 1: now = time.time() # check for incoming commands from arduino if self.ser.inWaiting() > 0: incoming = self.readline() logger.info("got serial command: '%s'", incoming) functions = { "next": self.client.next, "previous": self.client.previous, "pause": self.client.pause, } try: func = functions[incoming] func() # force redraw if anything changed if self.update(): last_display_update = 0 current_position = 0 except KeyError: logger.warning("ignoring unknown serial command '%s'", incoming) pass # check if song changed # TODO: use idle and poll (more often)? time_diff = now - last_song_update if time_diff > 2.5 or time_diff < -60.0: last_song_update = now if self.update(): last_display_update = 0 current_position = 0 # update arduino display time_diff = now - last_display_update if time_diff > 0.8 or time_diff < -60.0: last_display_update = now if self.playing: i = current_position if i - 1 + Config.display_length == len(self.line): i = 0 if i == 0: # allow people to start reading last_display_update += 2 if len(self.line) > Config.display_length: buf = self.line[i:i+Config.display_length] else: buf = self.line.ljust(Config.display_length, " ") i += 1 current_position = i else: buf = "-- PAUSED --".center(Config.display_width, " ").ljust(Config.display_length, " ") # always start at the beginning if we unpause current_position = 0 logger.debug("current_position = %s, buf = '%s'", str(current_position).rjust(3), buf) self.ser.write(bytes(buf, "ascii", "replace")) time.sleep(0.05) if __name__ == '__main__': d = Daemon() d.run()