1
|
#!/usr/bin/env python
|
2
|
#
|
3
|
# FabLab Radio by HackLab Terni
|
4
|
#
|
5
|
|
6
|
import pygame
|
7
|
from pygame.locals import *
|
8
|
import time
|
9
|
from rotary_class import RotaryEncoder
|
10
|
import json
|
11
|
import mpd
|
12
|
import os
|
13
|
import math
|
14
|
from subprocess import call
|
15
|
|
16
|
os.environ["SDL_FBDEV"] = "/dev/fb1"
|
17
|
|
18
|
# Define GPIO inputs
|
19
|
PIN_A = 13 # Pin 33
|
20
|
PIN_B = 26 # Pin 37
|
21
|
BUTTON = 6 # Pin 31
|
22
|
|
23
|
PIN_A_V = 16 # Pin 36
|
24
|
PIN_B_V = 12 # Pin 32
|
25
|
BUTTON_V = 5 # Pin 29
|
26
|
|
27
|
index = 0
|
28
|
numSta = 16
|
29
|
volume = 0
|
30
|
|
31
|
changed = True
|
32
|
play = False
|
33
|
changedVol = True
|
34
|
mute = False
|
35
|
|
36
|
# This is the event callback routine to handle events
|
37
|
def switch_event(event):
|
38
|
global index, numSta, changed, play
|
39
|
|
40
|
if event == RotaryEncoder.CLOCKWISE:
|
41
|
#print "Clockwise"
|
42
|
changed = True
|
43
|
index = index + 1
|
44
|
if index > (numSta - 1):
|
45
|
index = 0
|
46
|
elif event == RotaryEncoder.ANTICLOCKWISE:
|
47
|
#print "Anticlockwise"
|
48
|
changed = True
|
49
|
index = index - 1
|
50
|
if index < 0:
|
51
|
index = numSta - 1
|
52
|
elif event == RotaryEncoder.BUTTONDOWN:
|
53
|
#print "Button down"
|
54
|
play = not play
|
55
|
changed = True
|
56
|
#elif event == RotaryEncoder.BUTTONUP:
|
57
|
# print "Button up"
|
58
|
|
59
|
return
|
60
|
|
61
|
# This is the event callback routine to handle events
|
62
|
def volume_event(event):
|
63
|
global changedVol, mute, volume
|
64
|
|
65
|
if event == RotaryEncoder.CLOCKWISE:
|
66
|
#print "Clockwise"
|
67
|
changedVol = True
|
68
|
volume = volume + 2
|
69
|
if volume > 100:
|
70
|
volume = 100
|
71
|
elif event == RotaryEncoder.ANTICLOCKWISE:
|
72
|
#print "Anticlockwise"
|
73
|
changedVol = True
|
74
|
volume = volume - 2
|
75
|
if volume < 0:
|
76
|
volume = 0
|
77
|
elif event == RotaryEncoder.BUTTONDOWN:
|
78
|
#print "Button down"
|
79
|
mute = not mute
|
80
|
changedVol = True
|
81
|
#elif event == RotaryEncoder.BUTTONUP:
|
82
|
# print "Button up"
|
83
|
|
84
|
return
|
85
|
|
86
|
# draw some text into an area of a surface
|
87
|
# automatically wraps words
|
88
|
# returns any text that didn't get blitted
|
89
|
def drawText(surface, text, color, rect, font, aa=False, bkg=None):
|
90
|
rect = Rect(rect)
|
91
|
y = rect.top
|
92
|
lineSpacing = -2
|
93
|
|
94
|
# get the height of the font
|
95
|
fontHeight = font.size("Tg")[1]
|
96
|
|
97
|
while text:
|
98
|
i = 1
|
99
|
|
100
|
# determine if the row of text will be outside our area
|
101
|
if y + fontHeight > rect.bottom:
|
102
|
break
|
103
|
|
104
|
# determine maximum width of line
|
105
|
while font.size(text[:i])[0] < rect.width and i < len(text):
|
106
|
i += 1
|
107
|
|
108
|
# if we've wrapped the text, then adjust the wrap to the last word
|
109
|
if i < len(text):
|
110
|
i = text.rfind(" ", 0, i) + 1
|
111
|
|
112
|
# render the line and blit it to the surface
|
113
|
if bkg:
|
114
|
image = font.render(text[:i], 1, color, bkg)
|
115
|
image.set_colorkey(bkg)
|
116
|
else:
|
117
|
image = font.render(text[:i], aa, color)
|
118
|
|
119
|
surface.blit(image, (rect.left, y))
|
120
|
y += fontHeight + lineSpacing
|
121
|
|
122
|
# remove the text we just blitted
|
123
|
text = text[i:]
|
124
|
|
125
|
return text
|
126
|
|
127
|
def load_stations():
|
128
|
global stations
|
129
|
|
130
|
fp = open('/var/www/html/stations.json', 'r')
|
131
|
stations = json.load(fp)
|
132
|
fp.close()
|
133
|
|
134
|
client.clear()
|
135
|
for ind in range(numSta):
|
136
|
station = stations[ind]
|
137
|
name = station['name']
|
138
|
url = station['url']
|
139
|
#print ind, name, url
|
140
|
if url == "" or name == "":
|
141
|
client.add("silence.mp3")
|
142
|
else:
|
143
|
client.add(url)
|
144
|
|
145
|
client = mpd.MPDClient()
|
146
|
client.connect("localhost", 6600)
|
147
|
#client.setvol(0)
|
148
|
call(["amixer", "sset", "Master", str(0)])
|
149
|
|
150
|
load_stations()
|
151
|
|
152
|
print stations
|
153
|
print
|
154
|
pls = client.playlist()
|
155
|
for pl in pls:
|
156
|
print pl
|
157
|
print
|
158
|
|
159
|
# Define the switch
|
160
|
rswitch = RotaryEncoder(PIN_A,PIN_B,BUTTON,switch_event)
|
161
|
volswitch = RotaryEncoder(PIN_A_V,PIN_B_V,BUTTON_V,volume_event)
|
162
|
|
163
|
# Initialise screen
|
164
|
pygame.display.init()
|
165
|
pygame.mixer.quit()
|
166
|
screen = pygame.display.set_mode((320, 240))
|
167
|
pygame.mouse.set_visible(False)
|
168
|
|
169
|
txtsurf1a = pygame.Surface((120, 32))
|
170
|
txtsurf1b = pygame.Surface((200, 32))
|
171
|
txtsurf1 = pygame.Surface((320, 32))
|
172
|
txtsurf2 = pygame.Surface((320, 64))
|
173
|
|
174
|
# Display some text
|
175
|
pygame.font.init()
|
176
|
font1 = pygame.font.Font(None, 48)
|
177
|
font2 = pygame.font.Font(None, 32)
|
178
|
text = font1.render("FabLab Radio", 1, (250, 50, 50))
|
179
|
textpos = text.get_rect()
|
180
|
textpos.centerx = 160
|
181
|
screen.blit(text, textpos)
|
182
|
|
183
|
while True:
|
184
|
time.sleep(0.1)
|
185
|
|
186
|
if changedVol:
|
187
|
changedVol = False
|
188
|
|
189
|
txtsurf1a.fill((0, 0, 0))
|
190
|
if mute:
|
191
|
#print "mute"
|
192
|
#client.setvol(0)
|
193
|
call(["amixer", "sset", "Master", str(0)])
|
194
|
text = font2.render("Vol: mute", 1, (50, 250, 50))
|
195
|
else:
|
196
|
#print "volume",volume
|
197
|
if (volume == 0):
|
198
|
vol = 0
|
199
|
else:
|
200
|
vol = math.trunc(72*math.log10(volume))
|
201
|
#client.setvol(vol)
|
202
|
call(["amixer", "sset", "Master", str(vol)])
|
203
|
text = font2.render("Vol: " + str(volume), 1, (50, 250, 50))
|
204
|
|
205
|
txtsurf1a.blit(text, (10, 0))
|
206
|
screen.blit(txtsurf1a, (200, 214))
|
207
|
|
208
|
if changed:
|
209
|
changed = False
|
210
|
load_stations()
|
211
|
station = stations[index]
|
212
|
name = station['name']
|
213
|
url = station['url']
|
214
|
print index, name, url
|
215
|
|
216
|
if play and url != "" and name != "":
|
217
|
print "play"
|
218
|
txtsurf1b.fill((0, 0, 0))
|
219
|
text = font2.render("[play]", 1, (250, 50, 50))
|
220
|
txtsurf1b.blit(text, (80, 0))
|
221
|
text = font2.render("Sta: " + str(index+1), 1, (50, 250, 50))
|
222
|
txtsurf1b.blit(text, (4, 0))
|
223
|
screen.blit(txtsurf1b, (0, 214))
|
224
|
|
225
|
txtsurf1.fill((0, 0, 0))
|
226
|
text = font2.render(name, 1, (50, 250, 50))
|
227
|
txtsurf1.blit(text, (4, 0))
|
228
|
screen.blit(txtsurf1, (0, 32))
|
229
|
|
230
|
client.play(index)
|
231
|
else:
|
232
|
print "stop"
|
233
|
play = False
|
234
|
txtsurf1b.fill((0, 0, 0))
|
235
|
text = font2.render("[stop]", 1, (250, 50, 50))
|
236
|
txtsurf1b.blit(text, (80, 0))
|
237
|
text = font2.render("Sta: " + str(index+1), 1, (50, 250, 50))
|
238
|
txtsurf1b.blit(text, (4, 0))
|
239
|
screen.blit(txtsurf1b, (0, 214))
|
240
|
|
241
|
txtsurf1.fill((0, 0, 0))
|
242
|
text = font2.render(name, 1, (50, 250, 50))
|
243
|
txtsurf1.blit(text, (4, 0))
|
244
|
screen.blit(txtsurf1, (0, 32))
|
245
|
|
246
|
client.stop()
|
247
|
|
248
|
cs = client.currentsong()
|
249
|
if play and cs:
|
250
|
#print cs
|
251
|
#print
|
252
|
if 'title' in cs:
|
253
|
SongTitle = cs['title']
|
254
|
elif 'file' in cs:
|
255
|
SongTitle = cs['file']
|
256
|
|
257
|
txtsurf2.fill((0, 0, 0))
|
258
|
drawText(txtsurf2, SongTitle, (50, 50, 250), txtsurf2.get_rect(), font2, 1)
|
259
|
screen.blit(txtsurf2, (0, 150))
|
260
|
|
261
|
if 'name' in cs:
|
262
|
txt = cs['name']
|
263
|
txtsurf2.fill((0, 0, 0))
|
264
|
drawText(txtsurf2, txt, (250, 250, 50), txtsurf2.get_rect(), font2, 1)
|
265
|
screen.blit(txtsurf2, (0, 60))
|
266
|
|
267
|
txtsurf1.fill((0, 0, 0))
|
268
|
text = font2.render("genre", 1, (50, 250, 250))
|
269
|
txtsurf1.blit(text, (4, 0))
|
270
|
screen.blit(txtsurf1, (0, 120))
|
271
|
else:
|
272
|
txtsurf2.fill((0, 0, 0))
|
273
|
screen.blit(txtsurf2, (0, 60))
|
274
|
screen.blit(txtsurf2, (0, 150))
|
275
|
txtsurf1.fill((0, 0, 0))
|
276
|
screen.blit(txtsurf1, (0, 120))
|
277
|
|
278
|
for event in pygame.event.get():
|
279
|
if event.type == QUIT:
|
280
|
exit()
|
281
|
|
282
|
pygame.display.flip()
|
283
|
|