I’ve been tweaking my touch-screen Raspberry Pi radio. It’s optimised for the Pimoroni HyperPixel display, but it would work with any touch-screen, although it may need scaling for different sized screens.
Aside from the mpd/mpc music player and adding some radio stations, it doesn’t need any other libraries installing and should run on vanilla Raspbian. You’ll need some GIF images of logos, the ones I used are on the page for the old version of this program.
I’ve tidied up the display a bit, added a button to shut the system down and added a button that shows the track that is currently playing on Fip, my favourite radio station. This is actually rather useful as Fip’s music is famously eclectic and sometimes you just have to know what that achingly cool Belgian techno-influenced rockabilly-jazz tune is and who recorded it.
I can’t, it seems, easily do this for BBC radio, alas. France’s state broadcaster syndicates its ‘now playing’ track info as a JSON feed and I had a huge amount of, er, ‘fun’ working out how to parse this. Turns out you have to ‘drill down’ quite far in the data:
key = feed['levels'][0]['items'][3]
to extract a UUID number that you then need to use to look up the track name. And sometimes the ‘performer’ field is missing for some reason, so I added an exception for that. But at least it’s there. Unlike BBC radio.
And I learned a bit about handling JSON in Python.
I made a really cool Raspberry Pi radio a few years ago that you controlled from a web page that had ‘now playing’ info for Fip (culled from a twitter account) and from the BBC via Last.fm. It looks like the Last.fm kludge doesn’t work any more, and the BBC seems to have closed the ‘Backstage’ operation which provided API access to its ‘now playing’ data for independent websites like https://dyl.anjon.es/onradio/1 – which, oddly, still seems to work. I could screen-scrape that web page, I suppose, but it seems a bit unfair on Mr Jones. It is very frustrating the BBC doesn’t seem to do this any more – if anyone knows different I’d be grateful. Fip doesn’t even require an API key.
Anyway, here’s the Python program. It only fetches the Fip JSON data when you press the ‘fip now plays’ button so it doesn’t update all the time, and also does not bombard Fip’s servers with data requests.
#!/usr/bin/env python3
from tkinter import Tk, Label, Button, PhotoImage
import os, time, subprocess, json
from urllib.request import urlopen
def get_jsonparsed_data(url):
response = urlopen(url)
data = response.read().decode("utf-8")
return json.loads(data)
url = ("https://www.fip.fr/livemeta/7/")
time1 = ''
IP = subprocess.check_output(["hostname", "-I"]).split()[0]
class MyFirstGUI:
def __init__(self, master):
global fiplogo
self.master = master
master.title("HyperPixelRadio")
fiplogo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/fip100.gif")
self.label = Label(master, text="HyperPixel Radio by @blogmywiki", font=('Lato Heavy',25), fg = 'blue')
self.label.grid(columnspan=7, pady=20)
self.fip_button = Button(master, image=fiplogo, command=self.fip, height=100, width = 100)
self.fip_button.image = fiplogo
self.fip_button.grid(row=1, pady=10, padx=4)
r2logo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/radio2.gif")
self.r2_button = Button(master, image=r2logo, command=self.r2, height=100, width = 100)
self.r2_button.image = r2logo
self.r2_button.grid(row=1, column=1, padx=4)
r4logo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/radio4.gif")
self.r4_button = Button(master, image=r4logo, command=self.r4, height=100, width = 100)
self.r4_button.image = r4logo
self.r4_button.grid(row=1, column=2, padx=4)
x4logo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/4extra.gif")
self.x4_button = Button(master, image=x4logo, command=self.x4, height=100, width = 100)
self.x4_button.image = x4logo
self.x4_button.grid(row=1, column=3, padx=4)
r5logo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/5live.gif")
self.r5_button = Button(master, image=r5logo, command=self.r5, height=100, width = 100)
self.r5_button.image = r5logo
self.r5_button.grid(row=1, column=4, padx=4)
r6logo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/6music.gif")
self.r6music_button = Button(master, image=r6logo, command=self.r6music, height=100, width = 100)
self.r6music_button.image = r6logo
self.r6music_button.grid(row=1, column=5, padx=4)
wslogo = PhotoImage(file="/home/pi/Desktop/HyperPixelRadio/bbcws.gif")
self.ws_button = Button(master, image=wslogo, command=self.ws, height=100, width = 100)
self.ws_button.image = wslogo
self.ws_button.grid(row=1, column=6, padx=4)
self.down_button = Button(master, text="< VOL", command=self.down, height=5, width=10)
self.down_button.grid(row=2)
self.up_button = Button(master, text="shut down", command=self.shutdown, height=5, width=10)
self.up_button.grid(row=2, column=1)
self.close_button = Button(master, text="close app", command=self.close, height=5, width=10)
self.close_button.grid(row=2, column=2)
self.ip_button = Button(master, text="show IP", command=self.ipaddr, height=5, width=10)
self.ip_button.grid(row=2, column=3)
self.ip_button = Button(master, text="fip now plays", command=self.nowPlaying, height=5, width=10)
self.ip_button.grid(row=2, column=4)
self.stop_button = Button(master, text="pause", command=self.stop, height=5, width = 10)
self.stop_button.grid(row=2, column=5)
self.up_button = Button(master, text="VOL >", command=self.up, height=5, width=10)
self.up_button.grid(row=2, column=6)
self.nowPlayingLabel = Label(master, text=" ", font=('Lato Light',18), fg = 'black')
self.nowPlayingLabel.grid(row=4, columnspan=7, pady=0)
def ipaddr(self):
self.label.config(text=IP)
def nowPlaying(self):
feed=get_jsonparsed_data(url)
# Get UUID of song now playing so we can look it up
key = feed['levels'][0]['items'][3]
title = feed['steps'][key]['title']
try:
artist=feed['steps'][key]['performers']
except KeyError:
try:
artist=feed['steps'][key]['authors']
except KeyError:
artist="Artist unknown"
nowPlayingText = 'fip now playing:\n'+title.title()+' by '+artist.title()
self.nowPlayingLabel.config(text=nowPlayingText)
def fip(self):
print("fip!")
self.label.config(text='fip - France Inter Paris')
os.system("mpc play 1")
def r4(self):
print("BBC Radio 4 FM")
self.label.config(text='BBC Radio 4 FM')
os.system("mpc play 2")
def x4(self):
print("BBC Radio 4 Extra")
self.label.config(text='BBC Radio 4 Extra')
os.system("mpc play 7")
def r6music(self):
print("BBC 6music")
self.label.config(text='BBC Radio 6Music')
os.system("mpc play 3")
def ws(self):
print("BBC World Service News Stream")
self.label.config(text='BBC World Service News')
os.system("mpc play 4")
def r2(self):
print("BBC Radio 2")
self.label.config(text='BBC Radio 2')
os.system("mpc play 5")
def r5(self):
print("BBC Radio 5 Live")
self.label.config(text='BBC Radio 5 Live')
os.system("mpc play 6")
def stop(self):
print("stop MPC player")
self.label.config(text='-paused-')
os.system("mpc stop")
def close(self):
os.system("mpc stop")
root.destroy()
def up(self):
os.system("mpc volume +30")
def down(self):
os.system("mpc volume -30")
def shutdown(self):
print("shutting down system")
os.system("sudo shutdown now")
root = Tk()
#root.configure(background='cyan3')
root.configure(cursor='none')
root.attributes('-fullscreen', True)
my_gui = MyFirstGUI(root)
time1 = ''
clock = Label(root, font=('Lato Light', 48, 'bold'))
clock.grid(row=3, columnspan=7, pady=15)
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
# if time string has changed, update it
if time2 != time1:
time1 = time2
clock.config(text=time2)
# calls itself every 200 milliseconds
# to update the time display as needed
# could use >200 ms, but display gets jerky
clock.after(200, tick)
tick()
root.mainloop()