Building my mini Weather Man Pandora player with the RaspberryPi

The RaspberryPi is a neat mini device. I’m not going to go rave about it because there are plenty of those type of pages out on the interwebs.

A friend asked me to post up the general steps and config so here’s a quick put together. I’ll post further images and details later but here’s the brief of what I’ve got going.

Using an old PC Ribbon Cable I wired up my 16×2 LCD screen to a breadboard which I then with pointers from the amazing guide from Raspberry Spy (http://www.raspberrypi-spy.co.uk/2012/08/16×2-lcd-module-control-with-backlight-switch/) had my Pi all wired up.

Keep in mind a lot of this was quick and dirty scripting, I grabbed the same example Python code from the link above with one slight modification of changing our text variable to a fopen.

#!/usr/bin/python
#
# HD44780 LCD Test Script for
# Raspberry Pi
#
# Author : Matt Hawkins
# Site   : http://www.raspberrypi-spy.co.uk
# 
# Date   : 26/07/2012
#

# The wiring for the LCD is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)*
# 4 : RS (Register Select)
# 5 : R/W (Read Write)       - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0             - NOT USED
# 8 : Data Bit 1             - NOT USED
# 9 : Data Bit 2             - NOT USED
# 10: Data Bit 3             - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V**
# 16: LCD Backlight GND

#import
import RPi.GPIO as GPIO  
import time

# Define GPIO to LCD mapping
LCD_RS = 7  
LCD_E  = 8  
LCD_D4 = 25  
LCD_D5 = 24  
LCD_D6 = 23  
LCD_D7 = 18

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line  
LCD_CHR = True  
LCD_CMD = False

LCD\_LINE\_1 = 0x80 # LCD RAM address for the 1st line  
LCD\_LINE\_2 = 0xC0 # LCD RAM address for the 2nd line 

# Timing constants
E_PULSE = 0.00005  
E_DELAY = 0.00005

f=open('/root/Pianobar/output', 'r')

song = f.readline()  
artist = f.readline()

if len(song) > 16:  
    choppedsong = song[0:12] + "..."
else:  
    choppedsong = song[0:(len(song)-1)]

if len(artist) > 16:  
    choppedartist = artist[0:12] + "..."
else:  
    choppedartist = artist[0:(len(artist)-1)]

def main():  
  # Main program block
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
  GPIO.setup(LCD_E, GPIO.OUT)  # E
  GPIO.setup(LCD_RS, GPIO.OUT) # RS
  GPIO.setup(LCD_D4, GPIO.OUT) # DB4
  GPIO.setup(LCD_D5, GPIO.OUT) # DB5
  GPIO.setup(LCD_D6, GPIO.OUT) # DB6
  GPIO.setup(LCD_D7, GPIO.OUT) # DB7

  # Initialise display
  lcd_init()

  # Send some test
  lcd_byte(LCD_LINE_1, LCD_CMD)
  lcd_string(choppedartist)
  lcd_byte(LCD_LINE_2, LCD_CMD)
  lcd_string(choppedsong)

#  time.sleep(3) # 3 second delay

def lcd_init():  
  # Initialise display
  lcd_byte(0x33,LCD_CMD)
  lcd_byte(0x32,LCD_CMD)
  lcd_byte(0x28,LCD_CMD)
  lcd_byte(0x0C,LCD_CMD)  
  lcd_byte(0x06,LCD_CMD)
  lcd_byte(0x01,LCD_CMD)  

def lcd_string(message):  
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")  

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)

def lcd_byte(bits, mode):  
  # Send byte to data pins
  # bits = data
  # mode = True  for character
  #        False for command

  GPIO.output(LCD_RS, mode) # RS

  # High bits
  GPIO.output(LCD_D4, False)
  GPIO.output(LCD_D5, False)
  GPIO.output(LCD_D6, False)
  GPIO.output(LCD_D7, False)
  if bits&0x10==0x10:
    GPIO.output(LCD_D4, True)
  if bits&0x20==0x20:
    GPIO.output(LCD_D5, True)
  if bits&0x40==0x40:
    GPIO.output(LCD_D6, True)
  if bits&0x80==0x80:
    GPIO.output(LCD_D7, True)

  # Toggle 'Enable' pin
  time.sleep(E_DELAY)    
  GPIO.output(LCD_E, True)  
  time.sleep(E_PULSE)
  GPIO.output(LCD_E, False)  
  time.sleep(E_DELAY)      

  # Low bits
  GPIO.output(LCD_D4, False)
  GPIO.output(LCD_D5, False)
  GPIO.output(LCD_D6, False)
  GPIO.output(LCD_D7, False)
  if bits&0x01==0x01:
    GPIO.output(LCD_D4, True)
  if bits&0x02==0x02:
    GPIO.output(LCD_D5, True)
  if bits&0x04==0x04:
    GPIO.output(LCD_D6, True)
  if bits&0x08==0x08:
    GPIO.output(LCD_D7, True)

  # Toggle 'Enable' pin
  time.sleep(E_DELAY)    
  GPIO.output(LCD_E, True)  
  time.sleep(E_PULSE)
  GPIO.output(LCD_E, False)  
  time.sleep(E_DELAY)   

if __name__ == '__main__':  
  main()

Next step is to setup Pianobar (Pandora). Raspbian makes this very easy compared to my Fedora setup:

sudo apt-get install pianobar  

We then need to setup fifo and OnEvent Command, so; Pianobar config (/root/.config/pianobar/config):

user = EmailAddress  
password = Password  
autostart_station = StationID (eg. 12312321l3)

event_command = /root/Pianobar/OnEvent.sh  
fifo = /root/Pianobar/ctl  
Pianobar has the neat fifo method of allowing us to integrate external applications or scripts straight into Pianobar.  
mkfifo /root/Pianobar/ctl  

Now while Pianobar is running if we simply echo “N” >> /root/Pianobar/ctl we’ll change songs. (N is the keyboard command for next song by default).
Now create the OnEvent file (/root/Pianobar/OnEvent.sh)

#!/bin/bash

# create variables
while read L; do  
        k="`echo "$L" | cut -d '=' -f 1`"
        v="`echo "$L" | cut -d '=' -f 2`"
        export "$k=$v"
done < <(grep -e '^\(title\|artist\|album\|stationName\|songStationName\|pRet\|$

case "$1" in  
        songstart)
                echo -e "$title\n$artist\n$stationName" > /root/Pianobar/output
                python /root/Pianobar/LCDWrite.py

esac  

This is really a dirty method of writing song changes to the LCD screen but it works for now.

For our weather feature (/root/Pianobar/weather.sh) if we have our playback paused for over 6 minutes we’ll display the weather and only update it daily. You need to update the weather URL API, currently it’s setup for Melbourne, Australia.

#!/bin/bash
#
# Author: andrewklau
# 
# Weather Script using YahooApi
# Check if no music has been updated in last 6 minutes and display current weather

while true; do

if test `find "/root/Pianobar/output" -mmin +6`  
then  
    day=`date +"%u"`
    output=`sed '3,3!d' /root/Pianobar/output | cut -d ' ' -f2`
    if [ -z "$output" ]
    then

        weather=`curl --silent "http://weather.yahooapis.com/forecastrss?w=1103816&u=c" | awk -F '- '  '
/<title>/ { sub("</title>", "", $2) && l=$2 }
/<b>Forecast/ { getline; gsub("<.*", "", $2); printf("%s: %s\n", l, $2); exit }'`
        weather_low=`echo "$weather" | cut -d: -f4 | cut -d ' ' -f2`
        weather_high=`echo "$weather" | cut -d: -f3 | cut -d ' ' -f2`
        weather_status=`echo "$weather" | cut -d: -f2 | cut -d. -f1 | sed -e 's/^[ \t]*//'`
        weather_average=`echo $(((($weather_low+$weather_high))/2))`

        echo -n "L:$weather_low H:$weather_high\n$weather_status $weather_average\nWeather" > /root/Pianobar/output
        python /root/Pianobar/LCDWrite.py



    else
        if [ "$day" != "$output" ]; then

        weather=`curl --silent "http://weather.yahooapis.com/forecastrss?w=1103816&u=c" | awk -F '- '  '
/<title>/ { sub("</title>", "", $2) && l=$2 }
/<b>Forecast/ { getline; gsub("<.*", "", $2); printf("%s: %s\n", l, $2); exit }'`
        weather_low=`echo "$weather" | cut -d: -f4 | cut -d ' ' -f2`
        weather_high=`echo "$weather" | cut -d: -f3 | cut -d ' ' -f2`
        weather_status=`echo "$weather" | cut -d: -f2 | cut -d. -f1 | sed -e 's/^[ \t]*//'`
        weather_average=`echo $(((($weather_low+$weather_high))/2))`

        echo -n "L:$weather_low H:$weather_high\n$weather_status $weather_average\nWeather" > /root/Pianobar/output
        python /root/Pianobar/LCDWrite.py



        fi
    fi
fi

sleep 600;  
done  

Finally I’ve added a few buttons which I’ve connected up to the GPIO pins (8) and (9) for the two important functions, pause and next song. Finally we wrap this all up with one single bash file which we run in the background. (/root/Pianobar/lcdfunctions.sh)

#!/bin/bash
#
# RaspberryPI Button Input Checker
# Author: andrewklau
# Last Updated: 21/01/2013
#
# Reference GPIO Pins: https://projects.drogon.net/raspberry-pi/wiringpi/pins/
#

button=8 # 8 for SDA, 9 for SCL  
button2=9  
sh /root/Pianobar/weather.sh &  
while true; do

    # Button 1
    while [ `gpio read $button` = 0 ]; do
        echo "Changing Track" > /root/Pianobar/output
                python /root/Pianobar/LCDWrite.py
        sleep 3;
        echo "n" > /root/Pianobar/ctl
        sleep 10;
    done

    # Button 2
        while [ `gpio read $button2` = 0 ]; do
                output=`head -1 /root/Pianobar/output`
        day=`date +"%u"`
                if [ "$output" != "Playback Paused" ]
                        then
                                cat /root/Pianobar/output > /root/Pianobar/output.paused
                                echo "Playback Paused" > /root/Pianobar/output
                        else
                                cat /root/Pianobar/output.paused > /root/Pianobar/output
                fi
                echo "p" > /root/Pianobar/ctl
                python /root/Pianobar/LCDWrite.py
                sleep 10;
        done
        sleep 0.1
done  

Have this run in the background on boot (eg. /root/Pianobar/lcdfunctions.sh &)

Unfortunately all of this has been setup as root because root is required to communicate with the GPIO pins, as of current there are no other ways with the Pi :(

So in total you should have:
- /root/.config/pianobar/config - /root/Pianobar/ctl - /root/Pianobar/lcdfunctions.sh - /root/Pianobar/LCDWrite.py - /root/Pianobar/OnEvent.sh - /root/Pianobar/weather.sh

Start up Pianobar any time or at boot, feel free to add any thing else but please do share.

Some of the snippets came from various sources, my apologizes if I missed you for a reference.

comments powered by Disqus