So what is the PiFi Mini?
It's a feature rich "smart radio", it can play files from a thumbdrive, stream internet radio, and play songs from your iOS device via Airplay all while being controlled by a smartphone or web browser. I've decided to differentiate this particular version by calling it Mini because down the road I may also make a version that is meant to be fixed and stay in your entertainment centre. You can check out the manual I made here.
Why did I create this?
I own a few wifi radios, none have all of the features that I wanted so I decided I'd make my own.
- MPD backend
- Internet radio streams
- Local file playback and playlist support
- Airplay (shairport)
- Web Interface
- Allows for easy wifi configuration
- phpMP a web control client for MPD
- Various PiFi controls like Safe Shutdown, Reboot, Safely Eject USB Drive, Switch to AP Mode
- Online user manual
- Access Point fail-over mode
- What this means is you'll always be able to connect to the PiFi-Mini even if you're in a new network, simply boot the device and wait until you see a new wifi network appear. Once you connect to the PiFi's access point you can use the PiFi's web page to easily enter the necessary wifi info to connect to the current network you wish to. No messy command line editing of wpa_supplicant files necessary!
- Audio pops fixed - Only pops once when it turns on and once again when powered off.
- Script that monitors whether Airplay is active so that it is impossible for both MPD and Airplay to be playing at the same time.
- LCD display (Current song, player state, volume, IP address, wifi signal quality out of 100)
- While not absolutely necessary it is a very nice feature to have and only adds a little to the build cost
I've created a tutorial in two parts, part one covers everything but the LCD and is a good place to start, by the end of it you'll have a working smart radio that you can connect to your own speakers or stereo and control via smartphone apps or it's built in web interface. If you want to go further you can add an LCD display by following part two of the tutorial, this is purely optional. I will not have a tutorial covering the making of an enclosure or adding speakers, instead in the rest of this post I'll walk through my own build experience and if people want to copy my enclosure or my choice of built in amp/speakers they can.
Tutorial Part 1: Everything but the LCD
Tutorial Part 2: Adding an LCD screen
Or take the easy way out and download my pre-configured image (not available yet)
Building my Pi-Fi MiniWarning: The following is a long read but it covers all of the issues I ran into along the way.
You can see my original build thread over at the raspberry pi forums here.
My initial plan for this project was to focus on roughing out the software first, then roughing out the hardware, and finally polishing both. To begin with I needed to get my wifi dongle working, initially I chose one with an rtl8192u chipset simply because I heard it worked "out of the box" with raspbian. In the final design stages I realized some limitations of this dongle so I switched to an RT5370 based dongle instead.
*Quick warning about ebay dongles here.
Getting wifi up and running strictly via command line can be difficult, raspbian uses wpa_supplicant to connect to encrypted wifi networks and the config file is tricky when doing it by hand. I found the simplest way to do it was to start the desktop and use wpa_gui for the initial wifi setup.
MPD & MPC
Getting MPD (Music Player Daemon) installed proved to be relatively painless and so was MPC which is a command line client for MPD. This program is the main backend for the music player, it allows playback of local files as well as network streams. Since it is a well established program there are plenty of apps available to choose from for controlling it, for iOS my hands down favorite is MPoD. For Android I tried MPDroid, BitMPC and DroidMPD Client. All are decent and since they're free you might as well try them all, one feature that BitMPC had that I quite liked was the ability to add a podcast RSS feed.
(Note: The Shairport program is a bit of a legal grey area due to the means by which the program's author reverse engineered some of the elements. See this article and judge for yourself before installing.)
Next I installed Shairport to allow the PiFi Mini to act as an airplay device. Luckily I had found the updated tutorial first which used slightly different files to allow iOS 6 support. Installation was again pretty painless, some tweaking of the init.d file let me customize the name that is broadcast to airplay compatible devices.
Analog audio popping issue
I should mention at this point that when I was first getting started I followed some online advice for getting rid of the annoying popping when starting/stopping playback on the Pi when using the analog output. The fix at the time was to install Pulseaudio which acts like a go between to alsa, within one of the pulseaudio config files a module could be disabled that prevents the audio module from sleeping. It appeared that when the DAC in the audio out put would turn off it did so abruptly which caused the pop. For whatever reason installing this initially left me without sound and a few hours of troubleshooting got it sorted, still not sure what I did wrong. At this point I had zero popping with MPD since it was setup to use Pulseaudio, however I could not get shairport to work with pulseaudio. Eventually I found a different fix which required replacing the start.elf and fixup.dat files in the boot folder with modified versions, after this I uninstalled pulseaudio and now there is only 1 pop when the system starts and one when it stops. There is still a pop at the start when a song is played to the device over airplay but if you're playing numerous songs in a row there is no popping between songs.
One at a time...
While testing I realized that if I left MPD playing a song I could send a song over airplay and both would play out of the speakers at the same time. Now I'm still new to coding so my workaround to this is probably quite ham fisted but I found that using the command "sudo netstat -t" would show all tcp connections and when an Airplay connection was made that connection would always show "rfe". I set about writing a bash script that would run the netstat command, pipe it to grep to search out rfe, if doing so returned results my script would write "on" to a file in ram called airplay_state and it would pause MPD. I went further an had the script check if airplay had previously been running but now was stopped, if so it would resume playing MPD and write "off" to the file in ram. The purpose of writing it to a file in ram was so that other scripts I was using could easily tell if airplay was on or not, the main one being the LCD script.
Web Interface & Access Point Failover Mode
At this stage I had decided to make this a button-less system, solely controlled by a smartphone or computer since just about everyone has one on them nowadays or at least has a computer in their house. Because of this I needed to make the wifi setup part easier. If I want to bring this over to a friend's place I don't want to have to connect it to their TV and use a keyboard to edit my config files. I stumbled across this post about a nifty rc.local script that would try to connect to pre-defined networks and if none are available it would fail over into an ad-hoc mode. I didn't like that the network names had to be hard-coded into the script so I tweaked it so it relied on the existing wpa_supplicant.conf file. A dhcp server was also required to make it easier to connect to, also Android devices seemed to have issues with specifying a static IP and seemed to prefer to be assigned an ip by the device they were connecting to. The program dchpd handled this quite nicely. Next a webserver was required, lighttpd is a good lightweight server and I'd found a good tutorial here for that and php5, before long I was browsing to a placeholder page being hosted by my Pi!
The next challenge was figuring out how to a) take info the user entered into the webpage and pass it to another page or script and b) have a script run wpa_passphrase or write the wpa_supplicant.conf file directly. Since we had php installed I opted to use that, the user would enter their SSID, Encryption type, and password and using GET it would send it to a second php page. Within the second php page if the encryption was "open" it would write the into to a temporary wpa_supplicant.conf file then call a bash script that would copy it over the real file in /etc/wpa_supplicant/. If the encryption was wep, wpa, or wpa2 a text file would be written and the same bash script called, this bash script would read the info from the text file and use wpa_passphrase to generate the correct conf file and write it to /etc/wpa_supplicant/. At the end of the bash file the system reboots and if the info was all entered correctly by the user the Pi should reboot and connect to the desired network without issue. I'm sure "pros" are reading this and thinking I've probably done this very inefficiently but I'm no coder and it worked so I'm happy :) In doing it this way though I had to include another step, the commands I needed to run required root access and anything the webserver was doing was being ran as a user called "www-data" which did not have root permissions. I was able to give the user www-data special permissions only to run certain scripts and commands as root by editing the sudoers file.
Once I had the wifi config scripts figured out it was very simple to add a safe shutdown button and a reboot button. Since it wasn't costing me anything I added a "Switch to AP Mode" button, this is great for when you have friends over that want to play their music on the PiFi-Mini but you don't want to give everyone access to your home network.
MPD Web Client
Initially I installed phpmpreloaded, a very nice collection of the leading MPD web clients all packaged up and allowing the user to switch between them. Unfortunately this got off to a bad start and after talking with the developer (who was nice enough to talk with me) we discovered there were deprecated functions being used that were not compatible with php5. From monitoring /var/log/lighttpd/error.log and /var/log/syslog I was able to find the offending lines in the files and replace them with the appropriate commands. Ultimately since I didn't plan on using the web interface much (due to the nice Android and iOS apps) I opted to only keep phpMP which is very full featured albeit not as aesthetically pleasing as some of the others. I had in mind the tutorials I was going to write and I didn't want to have to cover all of the php fixes and phpMP works out of the box so that's the one I went with.
Auto Mounting USB drives
I found out that by default raspbian does not automatically mount external drives. Luckily I found a nice little program called usbmount that handles this for us. Adding a symlink in the music folder pointing at /media/usb makes it visible to MPD.
LCD Screen and LCD Proc
Initially I wired up the LCD screen using a breadboard and these handy cables that for some reason are called "duPont cables".
When I first wired up the screen I followed a guide online, regrettably this guide used one of the GPIO pins that changed between rev1 and rev2 which made my task of making it fully compatible with both difficult later. My initial LCD was the run of the mill yellow backlight version.
Once I had it wired up correctly a friend told me about LCD Proc which he figured would be easier than writing code that controlled the LCD directly. I later found there was an add-on for LCD Proc called MPDLCD however I initially ran into issues getting that to work so I wrote my own code to interface with LCDProc using this guide. Maybe it's just because I'm still new to coding but I found the documentation for LCDProc very confusing at first, eventually with trial and error and help from a few people I started getting somewhere.At the start the most important thing for me was having it display the IP just so I didn't have to have it connected to a monitor at boot, I could read the IP and then just ssh into it.
LCDProc (LCDd) doesn't support the GPIO interface of the Pi by default, the guide I followed linked to a special set of drivers that someone was nice enough to compile. Later when checking compatibility with a rev2 Pi I discovered that the custom drivers weren't compatible, on a rev 1 pin 13 is GPIO#21 but on a rev 2 it is GPIO#27. After quite a bit of digging I found another generous soul had fixed the issue and posted a recompiled hd44780.so driver file.
Setting up the LCDd.conf file is pretty straighforward once you have the proper drivers, however you need to then communicate with the daemon to write to the LCD, this has it's own protocol and is like learning a whole new language. I wrote a python script that pulls song and player info from MPC, checks the airplay state, and also displays the IP address. I commented the script pretty well so hopefully if people want to tweak it they can.
Later when I switched to a "prettier" blue LCD I found my scroll speed for the text was set to high, the text on blue LCD takes longer to fade and with the speed I had it set too would smear the text making it hard to read. I slowed down the scroll quite a bit and it works good now, for those that follow the tutorial and use a yellow background screen you might want to speed the scroll up again.
Custom PCB (not a requirement for building your own)
This wasn't really necessary but I wanted things to look nice and "finished", plus I'd been wanting to try out some of these cheap PCB manufacturers for awhile. Using KiCad, a free program, I designed a connection board and threw in a few extras like vias for a serial connection, a spot for a power switch, room for 6 buttons with pull up resistors, lcd contrast pot, LED backlight current limiting resistor. For $15 I got 10 5cm x 5cm boards shipped to me door, not too shabby! I realized I'd made a few oversights in the design, I have a nice large via for a +5V input but forgot to include a complimentary ground via. Luckily since I'd had the space I included a second set of vias for each the 13x2 Pi header and the 16x1 LCD header so I had lots of extra places I could solder a ground to. Eventually I plan on spending more time and making a better LCD shield PCB for the Pi but for now for anyone interested I'll include a link to my KiCad files and Gerber output in case anyone wants to use my own (slightly flawed) design.
I found a wooden box for $3 at the local dollar store that I figured would do nicely for a temporary enclosure.
At this point I was still using a little portable speaker for testing. Since the box was pretty much made out of balsa wood it was very light and easy to cut. I used a dremel and it was like cutting tissue paper really.
Mounting a Rev1 Pi that has no mounting holes
When the Pi first came out I was baffled by the fact they had omitted such a basic and crucial feature. They knew that the DIY community was lining up in droves to buy Raspberry Pi's so for them to be missing was a surprise. Furthermore they still have not released an official mechanical drawing of the Pi, there are ones floating around made by the community which range in accuracy from way out to very precise. Using the best drawings I could find and by taking my own measurements I made the drawing below in Skethup.
The standoffs are actually plastic spacers, I had to glue a nylon nut to the bottom of each and cut a slot in the side for the pcb to fit. Not the most elegant solution but it worked :).
Speakers & Amplifier
When I first set out to start this project I'd ordered some parts from www.dx.com a great site full of cheap stuff and a decent DIY electronics section. I opted for this 3W+3W amplifier board for $3.50 and for speakers I chose these which were $2.80 each and the required 3W. The only downside to ordering from dx.com is that it takes about 3 weeks for your stuff to arrive. While I was at a local surplus store I came across some Logitec Z110 powered speakers for $10 so I snapped them up thinking they'd be good for the time being. Taking apart the Z110's was not an easy task and if any others try it I recommend caution. Once apart though I was delighted to find the speakers had very robust magnets and best of all the speakers had brackets for screws. Ultimately due to these nice mounting brackets I opted to use them instead of the ones I ordered from dx.com, the sound quality is good however the one flaw with my final design is the speakers aren't enclosed and they really should be for optimal sound. Also, when my dx.com speakers arrived I realized I had misread the description and they were a lot smaller than I thought they were so I probably wouldn't have used them anyway.
At this point I my custom PCB's still had not arrived yet so I was using perfboard.
Designing a better case
A good friend of mine is a talented metal worker and has his own plasma table for cutting metal. I highly recommend him, you can see his work over at his website http://mint-design.ca/
A while back I had done some photography work for him so in exchange he gave me some credit, finally with this project I had a chance to spend it. I used Sketchup to design the box and do some 3D renderings, he took the file and converted it to the type he needed and cut out my design using 0.080" aluminum. The thinness was really overkill but since he already had another job he was working on using the same material he just added mine when cutting.
I know I listed way more dimensions than required :)
A 3D rendering I made using Sketchup and Kerkythea
The case being plasma cut over at http://mint-design.ca
Once cut the flat sheets still required bending, all the holes needed to be drilled. PEM nuts were installed rather than using sheet metal screws so it could be taken apart and reassembled repeatedly. Once bent and all of the holes drilled it needed to be sanded to remove all of the tooling marks.
For speaker grills I used 50mm fan grills, later once everything was together I thought of adding metal handles to further add to the look as well as provide a little more protection.
The USB ports presented a problem, since the case was metal I couldn't have the wifi dongle inside because all of the signal would be blocked. I also wanted to be able to plug in a thumb drive with music on it. I was eventually able to find panel mount USB cables on ebay which suited the task perfectly.
It still a bit of a jumble of wires but it's about as good as I could get it.
Its never really finished is it?
With the hardware side pretty much done I set about refining the software a bit. I used some CSS to make the webUI look quite a bit nicer. I put my graphic design skills to work and created what I think is a nice sleek logo and branded it PiFi as a play on words for HiFi. I even went so far as to create a full user manual which is stored on the PiFi Mini and is available via the webUI.
If you want to check out the user manual here is a link to it. Keep in mind that the hardware description is for my design and the LCD stuff would only pertain to those choosing to do part 2 of the tutorial as well but general use info still applies. This manual is bundled in a zip file in part 1 of my tutorial that contains all the files needed for the web interface.
Moving forward I may add software features and tweak things here or there. I've picked up two usb DAC's that I've yet to try out with the PiFi mini, for the audio that MPD handles it should be a matter of simply adding another audio output in the mpd.conf file, as for Airplay (Shairport) I'm not so sure.
Acknowledgements:I would like to thank the following people for their help while building this project:
Jason who posted his LCD tutorial over at Techfruits and took the time to email me back about some questions I had regarding talking to LCDProc.
James Laird who gifted the world with his airplay emulator shairport and was nice enough to try and help me troubleshoot some issues I was having getting shairport to work over ad-hoc (which ultimtely I never did get to work unfortunately).
Lee Dolsen who put together the phpmpreloaded package, unfortunately I didn't wind up using it due to php5 compatibility issues but he was very helpful with figuring out my issues.
Conrad from Mint Design who not only cut out the box design but helped me with basically every stage up to the final bent drilled and sanded case.
If I've missed anyone I'm sorry, I appreciate your help.
Resources and tutorials I've used:
Crackle free audio in MPD http://dbader.org/blog/crackle-free-audio-on-the-raspberry-pi-with-mpd-and-pulseaudio
Ad-hoc fail safe mode http://lcdev.dk/2012/11/18/raspberry-pi-tutorial-connect-to-wifi-or-create-an-encrypted-dhcp-enabled-ad-hoc-network-as-fallback/#comment-640
Shairport on Pi http://pi-raspberry.blogspot.ca/2012/08/shairport-raspberry-pi.html?showComment=1362968121371
MPD on Pi http://lesbonscomptes.com/pages/raspmpd.html and other google searches
Webserver using Lighttpd and php http://www.penguintutor.com/linux/light-webserver
Wiring up an HD44780 display - http://learn.adafruit.com/drive-a-16x2-lcd-directly-with-a-raspberry-pi/
Installing lcdproc and writing to it - http://www.tech-fruits.com/hardware/setting-up-lcd-via-gpio-on-raspi-part-1/
lcdproc developer guide - http://lcdproc.sourceforge.net/docs/current-dev.html
mpdlcd - https://github.com/rbarrois/mpdlcd
Audio glitch fix replacing start.elf and fixup.dat files https://github.com/raspberrypi/linux/issues/128
rtl8192 AP mode - http://blog.sip2serve.com/post/38010690 ... -rtl8192cu
Revised LCD proc drivers for Pi that support rev 2 http://www.raspberrypi.org/phpBB3/viewtopic.php?f=35&t=15967&start=50