14 Dec
2008
I don't like to get up early. Therefore, I stay in bed as late as possible and, as a result, never really set aside any time to check the news or even the weather before I head out the door. Although it would only take me an extra 3 minutes or so to read though stories or lookup the weather, the thought of turning on my monitor, entering my password, and going to the appropriate sites isn't terribly attractive for me at 5:30 in the morning.
Combine the above with a general distaste for the jarring sound that my alarm
makes got me thinking that there had to be a better way to get my morning started. I searched a bit to find MP3 alarm clocks (of which there are many) and initially used
KAlarm which served the purpose of waking me up with music quite adequately.
However, I work in the financial industry, where overnight news is advantageous to hear before getting to work. The markets might be up or down by large amounts (especially these days) based on what happened overnight, so at least figuring out what is going on before getting into the office is pretty helpful. This, combined with a day where I got stuck in the rain because I hadn't checked the weather, got me thinking -- how about an alarm clock that read news and weather from an RSS feed in addition to waking me up with a song.
Here's how I created it:
Basics:
- Python with urllib,
ElementTree, and re installed
- cron
-
mplayer (available on portage and apt)
- [optional] A playlist of MP3s or other songs that mplayer can play
-
festival -- a text-to-speech program (available on portage for gentoo and probably on apt too)
Steps
1) Install the necessary software. Emerge or apt-get mplayer and festival. Install ElementTree for python by following the instructions
here. The other packages, urllib and re were already installed on my python, but if thats not the case for you, a bit of Googling can help out here.
2) Pick one song at random from your playlist. The way I chose to do this was to use a quick bash line to pick a a random line from the playlist file (
playlist.m3u), and then create a new playlist with only the one song (
single_song.m3u). Another thought is to just start mplayer and play a random song directly from the big playlist, but this means that the music will keep playing until you kill mplayer. I wanted to have one song play and then have my news and weather start to be read, so I play only the one song from the small playlist.
#alarm.sh -- pulls together elements of alarm clock
#Written by ajlisy, 2008
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#Create file with single song
nlines=`cat playlist.m3u | wc -l`
random_line=`expr $RANDOM % $nlines + 1`
sed -n $random_line,${random_line}p playlist.m3u > single_song.m3u
#Play that song
mplayer -playlist single_song.m3u
# <...>
3) Set up the basic scripts for fetching and parsing the weather from the Yahoo! RSS feeds. The idea is that 2 simple python scripts,
get _weather.py and
get_news.py are called from the main bash script to populate the "script" files that are read by festival.
#get_news.py -- fetches headlines from RSS feed
#Written by ajlisy 2008
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
import urllib
import re
from elementtree.ElementTree import parse
def get_headlines(news_source,num_headlines):
news_rss_feed=parse(urllib.urlopen(news_source)).getroot()
raw_headlines=news_rss_feed.findall('channel/item')
headlines=[]
for i in range(0,num_headlines):
try:
headlines.append(raw_headlines[i].findtext('title').splitlines()[0])
except:
pass
return headlines
print "Today's top news stories "
YAHOO_NEWS = 'http://rss.news.yahoo.com/rss/business'
NYT_NEWS='http://www.nytimes.com/services/xml/rss/nyt/Business.xml'
print "Worldwide news from New York Times"
for element in get_headlines(NYT_NEWS,5):
try:
print element
except:
pass
print "Business news from Yahoo"
for element in get_headlines(YAHOO_NEWS,5):
try:
print element
except:
pass
#get_weather.py -- adapted from the tutorial on the Yahoo
# developers page found at
# http://developer.yahoo.com/python/python-xml.html
import urllib
from elementtree.ElementTree import parse
WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'
def weather_for_zip(zip_code):
url = WEATHER_URL % zip_code
rss = parse(urllib.urlopen(url)).getroot()
forecasts = []
for element in rss.findall('channel/item/{%s}forecast' % WEATHER_NS):
forecasts.append({
'date': element.get('date'),
'low': element.get('low'),
'high': element.get('high'),
'condition': element.get('text')
})
ycondition = rss.find('channel/item/{%s}condition' % WEATHER_NS)
return {
'current_condition': ycondition.get('text'),
'current_temp': ycondition.get('temp'),
'forecasts': forecasts,
'title': rss.findtext('channel/title')
}
weather=weather_for_zip(10038)
print "The current weather conditions are "+weather['current_condition']+" with a temperature of "+ weather['current_temp'] + " degrees."
print "Today's forecast is " + weather['forecasts'][0]['condition'] + " with a high of " + weather['forecasts'][0]['high'] + " degrees and a low of "+weather['forecasts'][0]['low'] + " degrees"
4) Link it all together with the
alarm.sh script that calls the individual "subroutines" mentioned above and assembles them into the alarm.
#alarm.sh
#Create file with single song
nlines=`cat playlist.m3u | wc -l`
random_line=`expr $RANDOM % $nlines + 1`
sed -n $random_line,${random_line}p playlist.m3u > single_song.m3u
#Play that song
mplayer -playlist single_song.m3u
#Create file to read
python get_weather.py > weather.txt
python get_news.py > news.txt
festival --tts weather.txt
festival --tts news.txt
Add the resulting script to your crontab for whenever you want to get up, and enjoy a better start to the day.