Raspberry Pi International Space Station traffic light

Whenever free time and clear night skies are present I like to keep an eye out for satellites moving across the sky. This used to mean actually going outside and waiting but now computer programs make it possible to schedule these moments of awe.

This time of year is perfect for spotting the International Space Station and there are dozens of the ISS trackers that would help to do this, but I wanted to make use of the Pi-Stop traffic light for Raspberry Pi from 4tronix - I have been using these at school with students learning Python and Scratch GPIO.

Example of the PiStop Photo: 4tronix

My system uses one traffic light and a Python program that scrapes the position of the ISS from http://api.open-notify.org/iss-now.json, a site which stores position data in the JSON format. The given lattitude and longitude is compared against a specific location on Earth. The lights come on when various conditions are met.

Red:

ISS is not within the visible area and will not move into it over the next three minutes.

Red/Amber:

ISS is not in the visible area, but it will move into it in the next three minutes.

Green:

ISS is visible and getting closer to your position.

Amber:

ISS is visible but is moving away from your position.

The code
###First import various bits that will be needed.
import RPi.GPIO as GPIO
import time
import urllib2
import json
import math 
import datetime

###This program runs on boot, so there is a minute delay here to allow the wifi connection to become active.
time.sleep(60)

###Turn warnings off, then turn all lights off.
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(26, GPIO.OUT)

###Assume ISS not visible and set state to red.
state = "red"

###Variables for storing current location.
hereLatitude = 52.127813
hereLongitude = -0.214285

###Set visibility range (about 800 miles in diameter)
north = 60
south = 40
west = -18
east = 18

###Function for scrapping ISS position from open-notify website.
def issPosition(n):
    try:
         req = urllib2.Request("http://api.open-notify.org/iss-now.json")
        response = urllib2.urlopen(req)
        obj = json.loads(response.read())
        if n == "lat":
            return obj['iss_position']['latitude']
        elif n == "long":
            return obj['iss_position']['longitude']
    except urllib2.HTTPError, e:
        print 'HTTPError = ' + str(e.code)

    except urllib2.URLError, e:
        print 'URLError = ' + str(e.reason)

    except httplib.HTTPException, e:
        print 'HTTPException'

    except Exception:
        import traceback
        print 'generic exception: ' + traceback.format_exc() 

###Function for changing colours
def changeLight(n):
    if n == "red":
        GPIO.output(26,True)
        GPIO.output(24,False)
        GPIO.output(22,False)

    elif n == "redAmber":
        GPIO.output(26,True)
        GPIO.output(24,True)
        GPIO.output(22,False)

    elif n == "green":
        GPIO.output(26,False)
        GPIO.output(24,False)
        GPIO.output(22,True)

    elif n == "amber":
        GPIO.output(26,False)
        GPIO.output(24,True)
        GPIO.output(22,False)

###Function to test if ISS is within ranges set earlier.
def issPassTest(lat,long):
    if lat > south and lat < north and long > west and long < east:
        return True
    else:
        return False

###Function to detect if ISS is getting closer
def towardsHereTest():
    def distanceFromHere():
         latDifferenceSquared = math.pow(hereLatitude - issPosition("lat"),2)
        longDifferenceSquared = math.pow(hereLongitude - issPosition("long"),2)
        return latDifferenceSquared + longDifferenceSquared
    firstCheck = distanceFromHere()
    time.sleep(5)
    secondCheck = distanceFromHere()
    print firstCheck
    print secondCheck
    if firstCheck > secondCheck:
        return True
    else:
        return False

###Main continuous loop 
while True:
    try: 
        if state == "red":
            changeLight("red") 
            currentLatitude = issPosition("lat")
            currentLongitude = issPosition("long")
            time.sleep(10)

            previousLatitude = currentLatitude
            previousLongitude = currentLongitude
            currentLatitude = issPosition("lat")
            currentLongitude = issPosition("long")

            differenceLatitude = currentLatitude - previousLatitude
            differenceLongitude = currentLongitude - previousLongitude

            ###Is the ISS going to pass over head in the next three minutes?
            for i in range(18):
                if issPassTest(currentLatitude, currentLongitude):
             state = "redAmber"
                    print state
                    print datetime.datetime.now() 
                currentLatitude += differenceLatitude
                currentLongitude += differenceLongitude
                print datetime.datetime.now() 
                print "red: ", currentLatitude, " ", currentLongitude 

        elif state == "redAmber":

            changeLight("redAmber")

            ###Is it here yet? If so, go green!
            for i in range(18):
                time.sleep(10)
                if issPassTest(issPosition("lat"), issPosition("long")):
                    state = "green"
                    print "green"
                    break
                elif i == 17:
                    state = "red"
                    print state

        elif state == "green":

             changeLight("green")

             while state == "green":

                ###Is it still getting closer? When not, go amber!
                if towardsHereTest():
                    print "getting closer"
                else:
                    state = "amber"
                print "amber -- moving away from here"

        elif state == "amber":

            changeLight("amber")

            while state == "amber":
                if issPassTest(issPosition("lat"), issPosition("long")):
                    print "amber"
                    time.sleep(10)
            else:
                    state = "red"
                    print "Red -- see you again soon!"

    ###If something goes wrong retrieving data, turn all lights off. 
    except:
        print "Error with the issPosition function"
        GPIO.output(26,False)
        GPIO.output(22,False)
        GPIO.output(24,False)

    continue

I have this program run on boot by adding this line to the Pi's crontab file:

@reboot python /home/pi/iss.py

The program runs continuously in the background until manually stopped.