This Sachsenwerk Olympia 59-3W from 1959 learned to play web radio and mp3s |
No drilling required - Minimally invasive connection of the Raspberry to the tube radio |
This post describes how to setup your Raspberry Pi to work as a web radio and an mp3 player based on mpd and Arch Linux. This description is a part of the TubeNetRadio project described in more detail under www.doc-diy.net/electronics/tubenetradio. In this project the Raspberry Pi is embedded in an old tube radio to add an internet radio and mp3 player functionality.
The user interface consists of just to buttons mounted in the back plate to avoid destroying the original look of the old radio. One button allows to step through radio stations stored in a file. The other one allows you to skip album-wise though your mp3 collection stored locally or remotely. In the following, the essential steps of the software setup are described. The hardware side is described under www.doc-diy.net/electronics/tubenetradio.
Main installation steps
- Installation of Arch and Python
- Installation of mpd/mpc
- The buttons and the player function
- The start script
Copy a fresh Arch image on the SD card. At the time of writing this was
ArchLinuxARM-2014.01-rpi. Configure and update your system. Arch lacks pretty much everything at the beginning. Follow one of the tutorials on the net.
Install base-devel for gcc and others. You will need it to compile the python-pip tool which in turn installs the RPi.GPIO.
pacman -Sy base-develInstall python2. Because python 3 and 2 are not compatible, the packages are split. The old python 2 is marked with a 2, the new version has no marking
pacman -S python2 python2-pipInstall mpd along with the Python interface using
pacman -S mpd mpc pacman -S python2-mpdImportant: In Jan 2014 python-mpd doesn't exist! Only the python2 version exists. This is the reason why you have to install the python2 stuff and not the new one. This will probably change soon.
To read out the buttons needed for the user interface you have to install RPi.GPIO by typing
python2-pip RPi.GPIORPi.GPIO is a comfortable Python interface to the GPIO connector on the Raspi board.
Starting mpd
Compared to Ubuntu, things turned out to be more complicated. I took me quite a time to sort out all the groups and user settings, including adding group read permissions for /home/pi. In case of trouble, I recommend to set up mpd on a linux PC and try to copy the settings of a working system.Have a look at this guide:
https://wiki.archlinux.org/index.php/Music_Player_Daemon#Starting_mpd_as_a_user
https://wiki.archlinux.de/title/Music_Player_Daemon
Worth reading is also this:
http://crunchbang.org/forums/viewtopic.php?pid=182574
Use the following listing of the home folder as reference. The user and the group of each file are specified in brackets (generated with tree -uga). Although alternative and better settings probably exist, the following proved to work for me.
[pi@alarmpi ~]$ tree -u -g -a . ├── [pi users ] .bash_history ├── [pi users ] .bash_logout ├── [pi users ] .bash_profile ├── [pi users ] .bashrc ├── [mpd audio ] .mpd │ ├── [mpd audio ] database │ ├── [mpd mpd ] log │ ├── [mpd mpd ] pid │ ├── [mpd mpd ] state │ └── [mpd audio ] sticker.sql ├── [root root ] lastradiopos ├── [root root ] lastsongpos ├── [pi audio ] music │ ├── [pi users ] Dive Deep │ │ ├── [pi users ] 01 - Morcheeba - Enjoy the Ride (ft Judy Tzuke).mp3 │ │ ├── [pi users ] 02 - Morcheeba - Riverbed (ft Thomas Dybdahl).mp3 │ │ ├── [pi users ] 03 - Morcheeba - Thumbnails.mp3 │ │ ├── [pi users ] 04 - Morcheeba - Run Honey Run (ft Bradley).mp3 │ ├── [pi users ] Love Deluxe │ │ ├── [pi users ] 01 - Sade - No Ordinary Love.mp3 │ │ ├── [pi users ] 02 - Sade - Feel No Pain.mp3 │ │ ├── [pi users ] 03 - Sade - I Couldn't Love You More.mp3 │ ├── [pi users ] Smolik │ │ ├── [pi users ] 01 - Smolik - SOS Songs feat. Gaba Kulka.mp3 │ │ ├── [pi users ] 02 - Smolik - Not Always Happy feat. Joao T. de Sousa.mp3 │ │ ├── [pi users ] 03 - Smolik - Memotion feat. Mika Urbaniak.mp3 │ └── [pi audio ] playlists │ └── [pi users ] myradiostations.m3u ├── [pi users ] tubeNetRadio.py └── [pi users ] tubeNetRadio.sh
After everything is set up correctly you should be able to launch mpd and manually control it with the frontend called mpc. Try mpc update, mpc ls, mpc add "", mpc play...
For mpd to start always at boot, you have to type the following
systemctl enable mpdand type
systemctl start mpdto start it immediately. Some info about starting services on boot in Arch Linux can be found here: https://wiki.archlinux.org/index.php/Systemd#Using_units
GPIO and the button routine
Raspberry Pi GPIO wiring plan for the buttons |
We have now mpd running and need some routine on top to poll the buttons and control the music according to the users needs. This is done using a single Python script which uses RPi.GPIO to understand the buttons and mpd-python to play the music. Using these two extensions we have everything on Python level.
Let me explain how the user interface works. There are just two buttons. One skips the radio stations which are stored in the file myradiostations.m3u in the music folder. The other button skips local mp3 music album-wise (not song-by-song) for faster navigation. All the functionality is contained in the following routine.
One issue that stole lots of time was the fact that the connection to the mpd server drops automatically and needs to reestablished or checked each time you want to perform an mpd operation. Skipping whole albums instead of songs adds some complexity to the script. It works basically by looking for the next song with a different album tag than the one currently played. For proper operation your songs have to be tagged.
The buttons have to be connected to GPIO02 and GPIO03 of the GPIO port. Resistors are not necessary since these pins have internal pull-ups.
#!/usr/bin/python2 # pyhton code for the tubeNetRadio project. tubeNetRadio is a Raspberry Pi # based internet radio / mp3 player with a minimalistic user interface # consisting of just two knobs (no display) # # Function: # # Button 1: skip to next radio station # Button 2: skip to next album of available mp3 archive # # www.doc-diy.net # # import mpd import RPi.GPIO as GPIO import os import time ############################################################################### # constants for readable code RADIO = 0 ALBUMS = 1 PRESSED = 0 # name of files where the recently played track/radio is stored lastsongfile = "/home/pi/lastsongpos" lastradiofile = "/home/pi/lastradiopos" # file with internet radio station playlist myplaylist = "myradiostations" # refers to "myradiostations.m3u" in playlist folder ############################################################################### # setup GPIO # pinout in chip nomenclature (BCM) buttonPin0 = 2 buttonPin1 = 3 GPIO.setmode(GPIO.BCM) GPIO.setup(buttonPin0, GPIO.IN) GPIO.setup(buttonPin1, GPIO.IN) ############################################################################## # connect to mpd server client = mpd.MPDClient() # create client object (this is how mpd works with # python) # Reconnect until successful while 1: try: status = client.status() #print("Initial connect") break except: client.connect("localhost", 6600) #print("Initial connect failed ...") time.sleep(1) ############################################################################### # set initial playmode. this setting decides if the player starts as mp3 player # or internet radio playmode = RADIO # initialize mpd client.clear() # clear playlist client.update() # update library client.load(myplaylist) # load playlist with radio stations client.play() # play music client.repeat(1) # repeat playlist ############################################################################### # generate 'recently played' files if missing (at first start for example) if not os.path.exists(lastsongfile): with open(lastsongfile, 'w') as f: f.write(str(1)) if not os.path.exists(lastradiofile): with open(lastradiofile, 'w') as f: f.write(str(1)) ############################################################################### # infinite button polling loop while True: input0 = GPIO.input(buttonPin0) input1 = GPIO.input(buttonPin1) # because mpd drops the connection automatically it has to be # checked or restablished before any operation. otherwise the # scripts stops while 1: try: status = client.status() break except: client.connect("localhost", 6600) print("Reconnect ...") ########################################################################### if input0 == PRESSED: # go to album mode or skip album if already in album mode if playmode == RADIO: playmode = ALBUMS client.clear() tracks=client.list('file') # get all files from data base # (doesn't load playlists with radio # stations) for t in tracks: client.add(t) # play song lastly played with open(lastsongfile, 'r') as f: songpos = int(f.read()) client.play(songpos) else: # get current song id songposcur = int(client.currentsong()['pos']) # get playlist # position of current song # create list of albums, replace empty entries with dummy plsinfo = client.playlistinfo() # get all track information for # playlist plsalbums = [] for alb in plsinfo: tmp = alb.get('album','-no-') # get albums and replace empty # entries by -no- plsalbums.append(tmp) # get album of current song songalbum = plsalbums[songposcur] # go through album list and search for the next song with a # differing album name for x in range(songposcur, len(plsalbums)): songpos = 0 # go to start of playlist, valid only if if # statement below fails if plsalbums[x] != songalbum: songpos = x break client.play(songpos) # play first song of next album # save current song id for next restart songpos = int(client.currentsong()['pos']) print(str(songpos)) with open(lastradiofile, 'w') as f: f.write(str(songpos)) f.truncate() # cuts all previous contents like digits time.sleep(0.1) # results in 10 Hz polling of button
Make the button Python script start automatically
We want the python script to start automatically after boot. Similarly to mpd
we need to place the corresponding .service file in /etc/systemd/system. Making this script run properly turned out to be a nightmare, probably due to the trial and error approach I followed. The final outcome that proved to work is here:
[Unit] Description=autostart tubeNetRadio mpd script After=default.target [Service] Type=oneshot ExecStart=/home/pi/tubeNetRadio.sh [Install] WantedBy=multi-user.targetThe first part specifies on what modules this service depends. The middle part says what command should be executed. The last part tells Arch what other modules need our service to start. Using some more elaborated settings smart things can be done. In makes sense to run this service after mpd and wlan started. Any improvements or comments are welcome.
The service has to be launched using
systemctl enable tubeNetRadio systemctl start tubeNetRadioHere is a listing of /etc/systemd/system after the launch for reference
[pi@alarmpi ~]$ tree /etc/systemd/system /etc/systemd/system ├── default.target.wants │ └── tubeNetRadio.service -> /etc/systemd/system/tubeNetRadio.service ├── getty.target.wants │ └── getty@tty1.service -> /usr/lib/systemd/system/getty@.service ├── multi-user.target.wants │ ├── avahi-dnsconfd.service -> /usr/lib/systemd/system/avahi-dnsconfd.service │ ├── cronie.service -> /usr/lib/systemd/system/cronie.service │ ├── haveged.service -> /usr/lib/systemd/system/haveged.service │ ├── mpd.service -> /usr/lib/systemd/system/mpd.service │ ├── netctl-ifplugd@eth0.service -> /usr/lib/systemd/system/netctl-ifplugd@.service │ ├── netctl@wlan0\x2dlothar\x2dbucher.service -> /etc/systemd/system/netctl@wlan0\x2dlothar\x2dbucher.service │ ├── remote-fs.target -> /usr/lib/systemd/system/remote-fs.target │ ├── rngd.service -> /usr/lib/systemd/system/rngd.service │ └── sshd.service -> /usr/lib/systemd/system/sshd.service ├── netctl@wlan0\x2dlothar\x2dbucher.service ├── sockets.target.wants │ └── avahi-daemon.socket -> /usr/lib/systemd/system/avahi-daemon.socket └── tubeNetRadio.serviceYou might have noticed, the tubeNetRadio.service launches an intermediate shell script called tubeNetRadio.sh:
#!/bin/bash sleep 1 && /usr/bin/python2 /home/pi/tubeNetRadio.pyThis script just launches the actual tubeNetRadio.py script after the delay of 1 second. The delay has been added because the service didn't start reliably, meaning that after some boots the buttons didn't react and I couldn't switch the radio stations or albums. The delay seems to help, but is a dirty workaround. I guess setting up the tubeNetRadio.service with some more care will solve the problem and make the intermediate script and the delay unnecessary.
Some facts
- mpd is very robust and always plays some music, even if the button routine fails.
- The time from power-on to music is about 30 s for Internet radio
- Tube heat-up time is about 15 s
- The "analog" two button interface proved to work much better then any smart phone remote control dropping the connection again and again.
- Radio can be controlled by non-freaks;)
Download
All source files and some extra info can be downloaded from https://github.com/doc-diy/tubeNetRadio or checked out directly with git:
git clone https://github.com/doc-diy/tubeNetRadio.gitDetails of the electrical connections and the way the Raspi is mounted can be found under
www.doc-diy.net/electronics/tubenetradio
Mounting an additional partition
You might have noticed that the Arch image expands to about 2 GB with 1.6 GB already occupied. This leaves just 400 MB for your mp3 collection. To add some volume you can expand the partition to use the whole SD card or create a new partition filling the remaining space. I went for the second option because of a lower risk of breaking the Linux. A second partition can be also easier accessed when the SD card is plugged into a computer, especially when FAT32 has been chosen. I can recommend the programm gparted for all formatting operations if you are under Linux.
Adding a second partition requires the fstab to be modified, see the last line below. The second partition was called /dev/mmcblk0p6 on my Arch Raspberry Pi.
# # /etc/fstab: static file system information # # <file system> <dir> <type> <options> <dump> <pass> /dev/mmcblk0p1 /boot vfat defaults 0 0 /dev/mmcblk0p6 /media/sdcard2gb/ vfat user,rw,umask=111,dmask=000 0 0
Setting the right options requires some experience. I recommend to have a look at this article: https://wiki.archlinux.org/index.php/fstab
I created the folder /media/sdcard2gb/ as the mount point, but you are free to choose. On the new partition the music resides in the folder music. Finally I deleted the original ~/music folder in home and made a softlink with the same name to the new partition with the music. The link command could be
ln -s /media/sdcard2gb/music ~/musicRemember, mpd was configured to look into the folder called ~/music for playable media.
Feel free to give me any feed back. I would be particularly interested in improving the launching script. Happy implementing!!!
Luk
No comments:
Post a Comment