Above Brum

I loved the idea of Above London (twitter) and as I utterly failed to see any Perseid meteors this week, I thought I’d shamelessly steal the idea for my locality, so I can at least hopefully see something light up in the sky in the not-too-distant future. :)

The account will send a message c. 30 minutes before an Iridium flare or an ISS flyby, based on information from heavens-above. It always sends the message even if the weather is bad, but does include the latest weather report so you can decide for yourself whether it’s worth popping outside.

http://twitter.com/abovebrum

Source code

There are three scripts: scrape, weather, and twitter. scrape runs daily to fetch the flare/ISS times, weather runs hourly to fetch the latest weather from Yahoo!, and twitter runs every five minutes to see if something is coming up that needs to be sent to Twitter.

weather

#!/usr/local/bin/python
#
# Run hourly to fetch latest weather from Yahoo!

import urllib, re, time

# Get the code for a different place from the Yahoo! web site or similar
code = 'UKXX0018'

weather = urllib.urlopen('http://weather.yahooapis.com/forecastrss?p=%s&u=c' % code).read()

# visibility might be useful for someone - I don't use it
# m = re.search('<yweather:atmosphere humidity="(\d*)"  visibility="([\d.]*)"  pressure="([\d.]*)"', weather)
# humidity, visibility, pressure = m.groups()

m = re.search('<yweather:condition  text="(.*?)"  code="(\d+)"  temp="(-?\d+)"  date="(.*?)"', weather)
text, code, temp, date = m.groups()

epoch = time.mktime( time.strptime(date, '%a, %d %b %Y %I:%M %p %Z') )

# Twitter bot doesn't actually use this, but it possibly could.
clear = 'NO'
# Blustery, Windy, Cold, Partly cloudy, clear, Sunny, Fair
if int(code) in [ 23, 24, 25, 29, 30, 44, 31, 32, 33, 34, 36 ]:
    clear = 'YES'

print "%s\t%s\t%s\t%s" % (epoch, clear, text, code)

scrape

#!/usr/local/bin/python
#
# Scraper for ISS and Iridium flare pages
# Runs once a day.

# Change these co-ordinates for your location
lat = 52.48
lon = -1.90

import urllib, re, time, sys
from datetime import datetime

dir = sys.path[0] + '/'

iss = urllib.urlopen('http://www.heavens-above.com/PassSummary.aspx?satid=25544&lat=%f&lng=%f&alt=114&tz=GMT' % (lat, lon)).read()
rows = re.findall('<tr class="(?:light|dark)row">\s*<td><a href="[^"]*">(.*?)</a></td>' + ('<td>\s*(.*?)\s*</td>' * 10), iss)
fp = open(dir + 'iss.tsv', 'w')
for row in rows:
    date, mag, start_time, start_alt, start_az, max_time, max_alt, max_az, end_time, end_alt, end_az = row
    # This will break around New Year time.
    timestamp = time.mktime(time.strptime('%s %s %s' % (datetime.now().year, date, start_time), '%Y %d %b %H:%M:%S'))
    out = (str(timestamp), mag, start_time, end_time, start_az, end_az, max_time, max_alt, max_az)
    fp.write("\t".join(out) + "\n")
fp.close()

iridium = urllib.urlopen('http://www.heavens-above.com/iridium.asp?Dur=7&lat=%f&lng=%f&alt=114&tz=GMT' % (lat, lon)).read()
rows = re.findall('<tr>\s*<td>(.*?)</td>\s*<td><a href="flaredetails[^"]*">(.*?)</a></td>\s*<td align=center>(.*?)</td>\s*<td align=right>(\d+)&#176;</td>\s*<td align=right>(\d+)&#176; \((.*?)\s*\)</td>\s*<td align=right>.*?</td>\s*<td align=center>.*?</td>\s*<td align=left><a href="[^"]*">(.*?)</a></td>', iridium)
fp = open(dir + 'iridium.tsv', 'w')
for row in rows:
    date, flare_time, mag, altitude, azimuth, compass, name = row
    timestamp = time.mktime(time.strptime('%s %s %s' % (datetime.now().year, date, flare_time), '%Y %d %b %H:%M:%S'))
    out = (str(timestamp), mag, altitude, azimuth, compass, name)
    fp.write("\t".join(out) + "\n")
fp.close()

twitter

#!/usr/local/bin/python
#
# twitter:
# Twitter Iridium flares and ISS flybys above Birmingham
#
# Copyright (c) 2009 Matthew Somerville. http://www.dracos.co.uk/

import urllib, urllib2, sys
from datetime import datetime, timedelta
import tweepy
from config import *
dir = sys.path[0] + '/'

def main():
    soon = datetime.today() + timedelta(minutes=30)

    weather = open(dir + 'weather.tsv').read()
    weather_epoch, weather_clear, weather_desc, weather_code = weather.strip().split("\t")

    flares = open(dir + 'iridium.tsv')
    for row in flares:
        epoch, mag, altitude, azimuth, compass, name = row.strip().split("\t")
        epoch = datetime.fromtimestamp(float(epoch))
        if soon >= epoch and soon < epoch + timedelta(minutes=5):
            s = u"Iridium flare: magnitude %s at %s, altitude %d\u00b0, in direction %d\u00b0 (%s), from %s. Weather: %s." % (
                mag, epoch.strftime('%H:%M:%S'), float(altitude), float(azimuth), compass, name, weather_desc
            )
            twitter(s)

    iss = open(dir + 'iss.tsv')
    for row in iss:
        epoch, mag, start_time, end_time, start_az, end_az, max_time, max_alt, max_az = row.strip().split("\t")
        epoch = datetime.fromtimestamp(float(epoch))
        if soon >= epoch and soon < epoch + timedelta(minutes=5):
            s = u"ISS pass: magnitude %.1f, %s\u2013%s from %s to %s, maximum altitude %d\u00b0 at %s in %s. Weather: %s." % (
                float(mag), start_time, end_time, start_az, end_az, float(max_alt), max_time, max_az, weather_desc
            )
            twitter(s)

def twitter(line):
    line = line.encode('utf-8')
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    return tweepy.API(auth).update_status(line)

main()

Navigation