Cardboard Raspberry Pi Wifi Internet Radio

What to do with the small cardboard box full of Raspberry Pi related junk, besides watch it sit slowly collecting dust? Surely it should be doing something interesting? Failing that it could be a wifi radio, I suppose.

Notes on how I converted a cardboard box full of bits into a cardboard box full of wifi radio.

It still collects dust.

Download the code
Photo set on Flickr

cardboard_rpi_radio_front
Cardboard Raspberry Pi internet radio front shot.

 
 

The hardware

 
Raspberry Pi model B
ST7565 LCD
2 Rotary encoders
4 digit, 7 segment display and a MAX72165124 driver
analogue panel meter
USB powered speakers
wifi dongle
cheap USB sound ‘card’ — on board audio conflicts with PWM GPIO

and a cardboard box
 
 
breadboard
 

GPIO Pin Map

pinout

Attempt at a circuit diagram, coming soon.

 
radio2All wired up

 
emptyboxbut will it fit into the box?

 
rammed_inNeedn’t have worried, it all rams in fine.

 
 

The software

Raspbian along with Gordon @ Drogon’s excellent Wiring Pi library.

A long time ago I almost learnt C, well enough to wangle a job as a C programmer (not very well). I don’t know Python at all and, like everyone else in the world, I think I can write PHP. It’s decided then everything will be bodged together in badly written C accompanied by even more badly written PHP.
 
 

Playing radio streams

I’m using mpd.

To set up, install (sudo apt-get you-know-the-rest) and edit the config file in /etc/mpd.conf

All we really need to change is the bind_to_address, set this to the RPi’s ip address. A little more fiddling is required to use the USB sound card, edit audio_output to use hw:1,0 instead of hw:0,0 in the config.

I created a playlist for every radio station I wanted to play. M3U playlists are stored in /var/lib/mpd/playlists At their most basic an M3U only needs to contain the URL of the the audio stream. For example XFM Manchester; URL http://ice-the.musicradio.com:80/XFMManchester pasted into an xfm_manchester.m3u in /var/lib/mpd/playlits

There’s a nice list of streaming radio stations here : http://www.listenlive.eu/uk.html

With a playlist created, restart mpd :

sudo service mpd restart

Now install an mpd client, funnily enough called mpc. With which we can :

mpc -h 192.168.0.66 load xfm_manchester.m3u
mpc -h 192.168.0.66 play

192.168.0.66 is the IP address of my RPi.

Full list of commands : http://linux.die.net/man/1/mpc

To load another play list :

mpc -h 192.168.0.66 clear
mpc -h 192.168.0.66 load radio4.m3u
mpc -h 192.168.0.66 play

 
To stop playback :

mpc -h 192.168.0.66 stop

 
All well and good except I want to listen to the BBC and their streaming URLs are awkward. Here’s a nice solution by Tim of Codeified to grab BBC stream URLs and save as M3Us for mpd : http://www.codedefied.co.uk/2011/12/24/playing-bbc-radio-streams-with-mpd/
 
 

Do things when we turn the knobs

I’m using two 2 bit rotary encoders. Datasheets are here. This wasn’t as straight forward as I’d hoped. After much faffing I stumbled on this solution : http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html Cut… Paste.
 
 

The clock

Left over from another project, a 4 digit 7 segment display hooked up to a MAX7219 driver. I’ve gone into detail on how I bodged this in another post. It displays the current system time, updated over NTP.
 
 

Displaying the download rate

I thought it might be nice to show the current download rate on an old analogue volt meter. The original scale was scanned and altered in Photoshop before being printed and stuck to the reverse (It’s not totally ruined I can always flip it in future) of the plate. It’s connected to GPIO 18 which is set up as PWM_OUTPUT via Wiring Pi.

I parse /proc/net/dev/ every second pulling out wlan0’s bytes received, subtracting the previous value to get bytes that second then divide by 1000, er… multiply by 8 to get kbps (I think). I then make sure its less than 1000 (the maximum value on my scale) and divide by some magic number such that when sent to pin 18 it’s at to the correct position on my scale. Okay, it takes some fiddling but after all that it’s pretty accurate-ish.
 
 

Bitmaps on the ST7565

I rewrote (I say rewrote, cut, pasted, bashed head against keyboard until it compiled is more truthful) Adafruit’s Arduino tutorial here : https://github.com/adafruit/ST7565-LCD and I’m happily able to display text and bitmaps.

I cobbled together some 128 x 64 station logos :

xfm    radio5_live    radio4_extra    6music    radio5_live

and went about converting them to a format I can use with the ST7565 LCD.

The ST7565’s memory map is divided into 8 pages of 128 bytes each, laid out something like this (note weird page order, it isn’t as specified in the datasheet) :

map ST7565 Memory Map

A 128×64 screen fits in 1K. Here’s a quick PHP (yay PHP!) script that takes a raw 1bpp image and converts to it to bytes suitable to dump to the ST765

// convert raw 1bit per pixel bitmap into code for lcd
$bitmapwidth = 128;
$bitmapheight = 64;

$fp = fopen("logo.raw","r");

$buf = fread($fp,1024*10);

for ($y=0;$y<($bitmapheight/8);$y++)
{
	for ($x=0;$x<$bitmapwidth;$x++)
	{
		$code=0;
 		for($dloop=0;$dloop<8;$dloop++)
 		{

			if (	ord($buf[$x+(($y*8)+$dloop)*$bitmapwidth]) != 0 )
			{
				$code += 1 << (7-$dloop); 
			}
 		}	
		echo $code.", ";
	}
}

 
 

Then I made it play Nyan Cat
 

 
 
Followed by Star Wars
 

 
 

Showing the currently playing song / artist

I intended to scrape html from the BBC station’s web sites for currently playing song title / artist, but I stumbled on some nice json feeds, the same feeds that the BBC use to update their own pages. 6 Music’s is here : http://polling.bbc.co.uk/radio/realtime/bbc_6music.json

nowplayingDisplaying current track info

A quick PHP script grabs the feed and parses title, artist and end time of the current song. I then store this locally for the main radio program to pull in. The fact that we know the end time of the song is helpful as it means we don’t have to constantly hammer the site in the hope that the song has changed if we know the song data we’ve already got is actually still playing.

The script :

#!/usr/bin/php5-cgi
<?php 
$localfile = "/home/pi/wifiplayer/bbc6_now_playing.txt"; 
$currentinfo = file($localfile); 
$last_song_end_time = $currentinfo[0]; 

// no need to grab new info if last song is still playing... 
if (time() > $last_song_end_time )
{
   $songdata = file_get_contents("http://polling.bbc.co.uk/radio/realtime/bbc_6music.jsonp");
   $end=0;
   // get song end time
   $pos1 = stripos($songdata, "end\":");
   if ($pos1 !== false) 
   {
      $endstart = $pos1 + 5;
      $endend = stripos(substr($songdata,$endstart), ",");
      if ($endend !== false)  $end = substr($songdata,$endstart,$endend);                                      
   }

   $artist="";
   $title="";

   // find artist 
   $pos1 = stripos($songdata, "artist\":"); 
   if ($pos1 !== false)  
   { 
      $artiststart = $pos1 + 9; 
      $artistend = stripos(substr($songdata,$artiststart), "\","); 
      if ($artistend !== false) $artist = substr($songdata,$artiststart,$artistend); 
   }                                                 
   
   // find title 
   $pos1 = stripos($songdata, "title\":"); 
   if ($pos1 !== false)  
   { 
      $titlestart = $pos1 + 8; 
      $titleend = stripos(substr($songdata,$titlestart), "\","); 
      if ($titleend !== false) $title = substr($songdata,$titlestart,$titleend);
   }                                                  
                         
   $fp = fopen($localfile, 'w'); 
   fwrite($fp, $end."\n".$artist."\n".$title."\n"); 
   fclose($fp); 
} 
?>

 
 
front2Finished, pride of place in the kitchen

8 thoughts on “Cardboard Raspberry Pi Wifi Internet Radio

  1. Looks amazing. I am inspired.
    On a different matter, are those Morris pix on your Flickr feed from Uppermill? Looks very familiar. Never been there without seeing a street parade.

  2. Thanks MrWheeliebin. Yup, Uppermill. Odd place, there’s always something going on. Yesterday there was a wrestling and gurning contest

  3. Coincidentally, I was looking for a source of now playing data since the BBC seem to have recently disabled their developer API that I had been using. After trying several other public API providers with no luck, it occurred to me to check the what happens on the live player, so I independently discovered polling.bbc.co.uk about half an hour ago.

    I arrived here after searching for some information about whether it would be a reliable substitute for an official API before I start using it. It seems I’ll go with it for now.

    I just thought I’d mention that in studying the json output, it actually projects the end time (unix timestamp) of the current track, so you don’t have to poll every 30 seconds. You could take note of the projected end time on the initial request and start polling say 30 seconds before the end of the track in case it gets cross faded early. Then when the track changes, lay off the polling again as you’re armed with the next track’s end time.

    Cheers
    Lee

  4. Hi Lee, that’s pretty much what the script does. Doesn’t bother grabbing the feed if the time is less than current end song time.

  5. Hi,
    I just found your awesome project on Reddit and now I’m trying to rebuilt it as a christmas-present.
    Everything is explained pretty well so far, thanks for sharing this with us. But I still got one question (so far): Where do I put all the code? I.e. at the part with the knobs you say “Cut? Paste.” Well… but where?
    And a little bonus-question: How did you get the Nyan-Cat running? I love this gimmick! 😉

    Cheers from Germany
    Florian

  6. Hi,

    Do you (or anyone else reading), have any more details on how you got the analogue meter hooked up to read the download rate?

    Thanks

    1. It’s nothing special. Attach your meter via a resistor to a PWM pin on the Pi and Ground.
      Write a simple Python script to send PWM values to the pin (Google will show you), the needle should move. Tweak for your specific scale.
      Python script to parse /proc/net/dev/ and pull out download rate, again Google will help.
      Merge the two. Send relevant value to meter depending on download rate. Meter moves accordingly.

Leave a Reply to David Cancel reply

Your email address will not be published. Required fields are marked *