Many Pies

Many Pies

Tuesday, October 20, 2009

Weather forecast via twitter - wycombeweather

Ages ago I thought it would be handy to have a local weather forecast delivered to my phone, for free. Then twitter came along and it looked like that might provide a possibility. By this time I'd come across the BBC weather RSS feeds.

I tried a couple of "RSS to twitter" services and both worked once and then never again. Google app engine looked like a good way of finding a server to do the stuff to join RSS to twitter. So I cobbled together bits of Python code and came up with this. (Update: September 2010 - updated to use oauth library. You'll need to register your app via dev.twitter.com to get the four keys below. )

(Paste in code from feedparser.org. Comment out the main program stuff.)
(Paste in outh stuff from http://github.com/mikeknapp/AppEngine-OAuth-Library/blob/master/oauth.py)


# Cobbled together from
# http://highscalability.com/using-google-appengine-little-micro-scalability
# http://pydanny.blogspot.com/2008/04/feedparser-does-not-work-with-google.html
import wsgiref.handlers
import urllib
from google.appengine.api import urlfetch
import base64
import feedparser
import StringIO

from google.appengine.ext import webapp

def getWeather():
      content = urlfetch.fetch("http://feeds.bbc.co.uk/weather/feeds/rss/5day/id/2111.xml").content
      d = feedparser.parse(StringIO.StringIO(content))
      if d.bozo == 1:
           raise Exception("Can not parse given URL.")
      return d['entries'][0]['title']

class WeatherText(webapp.RequestHandler):
def get(self):
     self.response.headers['Content-Type'] = 'text/html'

     self.response.out.write(getWeather())
     self.response.out.write('
supported by backstage.bbc.co.uk')


class UpdateWeather(webapp.RequestHandler):
def get(self):
     self.response.headers['Content-Type'] = 'text/plain'

     message = getWeather()
#      self.response.out.write(d['entries'][0]['title'] )
#      message = datetime.now().ctime()
     payload= {'status' : message,}
#      payload= urllib.urlencode(payload, True) Removed when switching to oauth client
# Get rid of degree marks because they turn out as question marks in the final tweet
#      payload = payload.replace('%3F','') degree marks work on twitter, appear as "deg" in txt, still wrong when main URL viewed
#      self.response.out.write(payload)

# Your application Twitter application ("consumer") key and secret.
    # You'll need to register an application on Twitter first to get this
    # information: http://www.twitter.com/oauth
     application_key = "im_not_telling_you"
     application_secret = "nor_this"
  
    # Get these from http://dev.twitter.com/apps/your_app_number/my_token
     user_token = "this_is_a_secret"
     user_secret = "this_is_definitely_a_secret"
  
    # In the real world, you'd want to edit this callback URL to point to your
    # production server. This is where the user is sent to after they have
    # authenticated with Twitter.
     callback_url = "%s/verify" % self.request.host_url
  
     client = TwitterClient(application_key, application_secret, callback_url)
     result = client.make_request("http://api.twitter.com/1/statuses/update.xml", token=user_token, secret=user_secret, additional_params=payload, protected=False, method=urlfetch.POST)
# Removed when oauth implemented
#      base64string = base64.encodestring('%s:%s' % (login, password))[:-1]
#      headers = {'Authorization': "Basic %s" % base64string}
#
#      url = "http://twitter.com/statuses/update.xml"
#      result = urlfetch.fetch(url, payload=payload, method=urlfetch.POST, headers=headers)
#
     self.response.out.write(result.content)


def main():
  application = webapp.WSGIApplication([('/', WeatherText),
('/updateweather',UpdateWeather)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()

 You can see the results at twitter.com/wycombeweather and wycombeweather.appspot.com. If you want to do it for your local UK weather you'll need to change the figure 2111 above and use your own twitter account.