1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#!/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.WARNING)
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)
logger.debug("connected. waiting for client greeting")
# 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"):
log.error("Got reply: '"+incoming+"'")
raise Exception("Wrong or no client greeting")
self.ser.timeout = 1
logger.debug("got client greeting")
self.client = mpd.MPDClient()
self.client.connect("localhost", 6600)
logger.debug("connected to mpd")
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()
try:
self.line = incoming["artist"] + " - " + incoming["title"]
except KeyError:
self.line = " -- NO INFO --"
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()
|