Monday, 18 April 2016

KitchenPi: an internet radio for my kitchen

We needed a radio in the kitchen to replace our Bush DAB/FM portable which has put in good service, although DAB reception in our area has never been great.

As space is at a premium, I wanted the new radio to take up as little space as possible.

So I came up with the idea of building something that would fit under the eye-level kitchen cabinets, behind the decorative molding.

This is another wifi Raspberry Pi powered internet radio, similar in operation to two previously described designs (the Radio Caroline inspired radio & the Insomniacs Bedside Radio).

KitchenPi fits within the 50mm pelmet

all that is visible is the glow of the blue lights! (Oh, and the power supply)

This is my first Pi powered radio to include an integrated audio amp and speakers.

Basic operation

KitchenPi just has a push-button switch and a rotary volume control. When powered on via the wall (mains) switch, the Pi boots and after 20-30 seconds starts playing.

Each time the push button is pressed, the program selects the next program source, the text-to-speech program eSpeak announces the source (e.g. "Radio Caroline") and then the stream starts.

The current configuration includes 5 internet radio streams and a music player (i.e. randomised music files).

functional testing

That's about it. The radio is turned off via the mains switch (I know...brutal).

The electronics

The audio amplifier design is pretty much covered in an earlier post on the NJM2073D. The final circuit  looks like this:-

one of two identical channels

The volume control has a logarithmic law because our hearing is not linear (i.e. we notice a doubling of sound level as being "a bit louder!").

As mentioned in the earlier post, this design is not optimal for use with the Pi as there is far more gain available than actually required.

And as a result of my tests on the Adafruit USB Audio adapter I decided there was no real benefit in using the Adafruit module, rather than the Pi jack socket.

The Pi audio output circuit (from the jack) includes basic filtering and looks like this:-

extract from the Raspberry Pi circuit diagram

In the final circuit I decided to add a 1nF capacitor across the 10K volume control to improve audio and restrict bandwidth to about 16kHz. This seemed to sound better and it improved the shape of the output for the 8kHz sine wave test.

1nF capacitor added (right trace)

The sound quality is also improved as a result of "baffling" the speakers. The enclosure consists of a 5 sided acrylic box, where the 6th side is effectively closed when the unit is screwed to the base of a kitchen unit.

Rear view before adding acrylic sides to front panel

The enclosure sides were cut from an A3 sized sheet of 3mm thick blue acrylic and glued together with rigid plastic adhesive.

I cut large holes for the speakers using my largest tank cutter (58mm diameter). The speakers are protected from probing fingers by 100mm finger safety guards, the kind designed for cooling fans (less than £1 each via Amazon).

Power supply and amp board

I'm using a 12V dc 1A supply (from Spiratronics) with a 5Volt switching regulator for the Raspberry Pi.

The switch logic is reversed from previous projects, only because this made the wiring and component placement slightly easier.

The 10uF capacitor is really just included as a physical connection point for the wires running to the LEDs and the wires running to the power/amp board. (i.e. the wires are soldered to the capacitor leads, and the capacitor leads are clamped by the terminal block connecting the incoming 12V supply).

12V power break-out

I did try a couple of blue/UV LEDs initially, but the wavelengths of the blue LED and blue acrylic did not match, so much of the light was filtered out

The software

As in my previous internet radio projects I've used a fairly simple Python program:-
#Plays random music player (Juke Box) or selected internet radio stream
#Pressing button (input 7) switches to next source from list

import os
import psutil
#Import the time library
import time
#Import the Raspberry Pi library which controls the GPIO
import RPi.GPIO as GPIO

PLAYER = "mplayer"
MUSIC = "/home/pi/Music"

MusicSource = 0

def SelectSource(mSource):
    RADIO_CAROLINE = ""        #128k
    PLANET_ROCK = "" #112k
    RADIO_TWO = ""        #128k
    RADIO_FOUR = ""        #128k
    WORLD_SERVICE = ""    #48k mp3

    JukeBox = 0
    RadioCaroline = 1
    PlanetRock = 2
    RadioTwo = 3
    RadioFour = 4
    WorldService = 5

    if mSource > 5:
        mSource = JukeBox
    if mSource == RadioCaroline:
        #start radio
        os.system('espeak -ven+f4 -s110 -k5 "Radio Caroline"')
        os.system('mplayer -cache 64 -playlist ' + RADIO_CAROLINE + ' &')
    elif mSource == PlanetRock:
        #start radio
        os.system('espeak -ven+m5 -s100 -k5 "Planet Rock"')
        os.system('mplayer -cache 64 ' + PLANET_ROCK + ' &')
    elif mSource == RadioTwo:
        #start radio
        os.system('espeak -ven+f1 -s100 -k5 "BBC Radio two"')
        os.system('mplayer -cache 64 -playlist ' + RADIO_TWO + ' &')           
    elif mSource == RadioFour:
        #start radio
        os.system('espeak -ven+m1 -s100 -k5 "BBC Radio Four"')
        os.system('mplayer -cache 64 -playlist ' + RADIO_FOUR + ' &')
    elif mSource == WorldService:
        #start radio
        os.system('espeak -ven+m3 -s110 -k5 "The BBC world service"')
        os.system('mplayer -cache 64 -playlist ' + WORLD_SERVICE + ' &')
        #start Juke-Box
        os.system('espeak -ven+f2 -s90 -k9 "play that funky music White boy"')
        os.system('mplayer -shuffle -playlist ' + MUSIC + '/playlist &')
    return mSource


#Clear the current GPIO settings
#Set mode to use Raspberry Pi pins numbers
#Set connector pin 7 to be an input

#Set volume
os.system('amixer  sset PCM,0 100%')

#update JukeBox playlist
os.system('find '+ MUSIC + ' -type f -iname \*.ogg -o -iname \*.wma -o -iname \*.mp3 > ' + MUSIC + '/playlist')

#get MusicSource from last time the program was run
file_source = open('/home/pi/LastSource','r')
MusicSource = int(
if MusicSource < 0:
    MusicSource = 0        #default to JukeBox

MusicSource = SelectSource(MusicSource)

#Create a LOOP that runs & runs (...until you shutdown)
while True:
    switch = GPIO.input(7)
    #the switch is normally "high" (True)
    if switch == False:
        #music source change, so kill player
        for proc in psutil.process_iter():
            #debug  print
            if == PLAYER:
        MusicSource += 1
        MusicSource = SelectSource(MusicSource)
        #save to file
        os.system('echo ' + str(MusicSource) + ' > /home/pi/LastSource')
        #switch debounce
        while switch == False:       
            switch = GPIO.input(7)       

    #Reduce cpu load

As before (see details) this program is run automatically by modifying /etc/local.rc.

You will also need to install python-psutil and espeak. From a command line in terminal, try this:-

sudo apt-get install python-psutil
sudo apt-get install espeak

more to do

If/when time permits I may work on the following.

Audio noise; As already mentioned, the audio amp has too much gain for this application. There is some low level random & intermittent background noise with the volume turned right down. The primary source of this noise appears to be the wifi dongle.

This noise is swamped by music, and compared to many conventional radios (FM as well as AM) is really not too bad. My family don't notice it.

But I know its there!

And the engineer inside my head says "...we can do better than this...". So once I have the additional components that I need, I will determine whether reducing the audio gain by applying negative feedback results in any improvement.

web interface; Using a simple push-button to change channels is fine as long as you don't need too many options. However, by creating a web interface I should be able to extend the range of stations (and maybe add podcasts, BBC iPlayer Radio & so on) by allowing the use of smart phone/iPad to select media.


People in kitchens often have sticky fingers. My use of cheese-head screws and finger guards could make this radio difficult to keep clean.

My original plans were for a radio mounted high up, on top of the kitchen cabinets, with remote controls. But this would come with its own set of problems.

EDIT 26-May-2016

KitchenPi modifications

KitchenPi has been running about 6 weeks and giving great service. Here are a few more comments and recent modifications.

Station ID announcement

When switching stations, the station announcement (e.g. "Radio Caroline") was found to be a bit loud. In some cases, it seemed louder than much of the program content. So I've modified the code to lower the volume for espeak using the "-a" variable:-

os.system('espeak -ven+m5 -s100 -k5 -a 30 "Planet Rock"')

Setting a value around 20-30 seems about right. This is done for all espeak lines within the program.

Stream drop-out

Just once in a while, usually during breakfast, we lose a stream. Sometimes this coincides with the microwave being used. Unfortunately the microwave is located directly in-line between KitchenPi and our wifi router.

I was hoping to move up from 2.4GHz to 5GHz to see if this would provide a more reliable link. But as you will see from my post on 5GHz wifi there seems to be a problem playing BBC streams via mplayer on the Raspberry Pi.

I now suspect this is an mplayer problem, but don't have much to go on at the moment (e.g. it works fine with Radio Caroline and Planet Rock streams, and it works fine on 2.4GHz with all streams). So I'm sticking with 2.4GHz for now.

However, to recover from the very occasional loss of stream, I've modified the Python code to check every 60s whether mplayer is still running. Here are the code modifications highlighted in red text:-

MusicSource = SelectSource(MusicSource)
LoopCount = 0
PlayerHasStopped = False

#Create a LOOP that runs & runs (...until you shutdown)
while True:

    LoopCount += 1
    switch = GPIO.input(7)
    #the switch is normally "high" (True)
    if switch == False:
        #music source change, so kill player
        for proc in psutil.process_iter():
            #debug  print
            if == PLAYER:
        MusicSource += 1
        MusicSource = SelectSource(MusicSource)
        #save to file
        os.system('echo ' + str(MusicSource) + ' > /home/pi/LastSource')
        #switch debounce
        while switch == False:       
            switch = GPIO.input(7)       
    #check whether player is still running
    if LoopCount > 300:
        LoopCount = 0
        PlayerHasStopped = True
        for proc in psutil.process_iter():
             if == PLAYER:
                PlayerHasStopped = False
        if PlayerHasStopped == True:
            MusicSource = SelectSource(MusicSource)

    #Reduce cpu load

I've only been testing this for a couple of far, so good.

Audio noise

I still have a small noise issue which I now know is due to the wifi dongle. As it scans for access points you can hear a background click which corresponds to the dongle blue light flashing.

The noise level is the same, irrespective of volume setting. In a way this makes it more difficult to deal with than it would be if the level went up and down with the volume.

As mentioned in the main text, its a problem to no-one but me. You can't hear it at all when music is playing. It is only noticeable in the gaps between speech and when the system is booting up.

I added ferrite beads to the left & right wires at the volume control input/Pi output (which probably hasn't made any difference) and two more to the pin 7 inputs to the NJM2073D amps (which I think has reduced the level a little).

Like most audio equipment, you also get noise when you hold a mobile phone close to kitchenPi, when the phone is actively communicating with the service.

But basically, KitchenPi is working great!

No comments:

Post a Comment