When To Leave

I’ve been using Waze for a long time now and I love how it can predict very accurately how much time a drive somewhere would take. However, I didn’t like the fact that when I want to know when to leave one place to get to another, I had to keep re-opening the app and to check whether I would arrive on time if I left at that exact moment.

So I wrote a little something to find out when I need to leave.

I took the opportunity to learn some bash scripting, since I’m new to Unix. I welcome any critique of my work, if you have any.

The script queries the Google Geocoding API for both addresses and sends a routing request to Waze’s servers (warning: that’s somewhat of an unstable hack there). It then polls every now and then and when you have to leave, it sends a notification using Boxcar to your phone. It then nags you until you Ctrl-C the script (yeah, I didn’t care to make something prettier). If you open the notification in Boxcar and click the link, it opens Waze on the spot you want to go and all you need to do is set that as your destination.

Please note that this script Works On My Machine and I don’t guarantee it would on yours too.

What You Need:

  1. An iPhone with Boxcar (it’s free) installed.
  2. A Unix machine (I’m using Mac OSX Lion).

Setup:

  1. Go to Boxcar and create a new provider. Note down its API key and the email you registered with.
  2. Copy the script below to a wtl.sh file and make it executable. Change the two variables at the top of it to the API key and email you kept when you registered for Boxcar.
  3. Create a file called wtl.presets with presets you want to use, such as home or work. The file’s structure is lines of: [preset name] [address]
    The preset’s name must not include spaces.

Calling It:

./wtl.sh [address/preset of origin] [address/preset of destination] [when to arrive] [minutes head-start]
  • Address / Preset – Either a well-defined address (e.g. 1600 Pennsylvania Avenue, Washington, DC or even The White House – if Google can find it automatically on a map, then you’re good) or a preset from the file (see #3 above).
  • When To Arrive – The time you want to arrive at your destination, formatted as %Y-%m-%d %H:%M (e.g. 2011-12-13 15:00).
  • Minutes Head-Start – How many minutes you want the notifications to start coming before you need to leave.
Example: ./wtl.sh home "The Western Wall" "2011-12-05 10:00" 10

This will notify me 10 minutes before I need to leave home to get to The Western Wall at 10am, December 5th, 2011.

Future Work:

Writing a web application that would replace this bash script is a great direction, since a native iOS application would be somewhat useless here, since it can’t poll the server while closed.

The Source Code:

#!/bin/bash

BOXCAR_EMAIL=#Add your Boxcar email here
BOXCAR_API_KEY=#Add your Boxcar API key here

MINS_BEFORE=$4
EPOCH_TO_ARRIVE=`date -j -f "%Y-%m-%d %H:%M" "$3" "+%s"`

FROM_ADDRESS=`grep "$1" wtl.presets | awk '{ $1=""; gsub(/^ /,""); print }'`

if [ "$FROM_ADDRESS" = "" ]; then
    FROM_ADDRESS=$1
fi

FROM_ADDRESS=`echo $FROM_ADDRESS | sed 's# #+#g'`

TO_ADDRESS=`grep "$2" wtl.presets | awk '{ $1=""; gsub(/^ /,""); print }'`

if [ "$TO_ADDRESS" = "" ]; then
    TO_ADDRESS=$2
fi

TO_ADDRESS=`echo $TO_ADDRESS | sed 's# #+#g'`
FORMATTED_2=`echo $2 | sed 's# #+#g'`

echo Looking up origin address...

ORIGIN=`curl -s --get http://maps.googleapis.com/maps/api/geocode/json --data sensor=false --data address=$FROM_ADDRESS | ./jsawk 'if (this.status != "OK" || this.results.length != 1) return "ERROR"; return "x%3A" + this.results[0].geometry.location.lng + "+y%3A" + this.results[0].geometry.location.lat;'`

if [ "$ORIGIN" = "ERROR" ]; then
    echo Unable to parse origin address
    exit
fi

echo Looking up destination address...

DESTINATION=`curl -s --get http://maps.googleapis.com/maps/api/geocode/json --data sensor=false --data address=$TO_ADDRESS | ./jsawk 'if (this.status != "OK" || this.results.length != 1) return "ERROR"; return "x%3A" + this.results[0].geometry.location.lng + "+y%3A" + this.results[0].geometry.location.lat;'`

if [ "$DESTINATION" = "ERROR" ]; then
    echo Unable to parse destination address
    exit
fi

echo Starting time calculations.

while [ true ]
do
    TIME_TO_DRIVE=`curl -s --get http://www.waze.co.il/RoutingManager/routingRequest -d from=$ORIGIN -d to=$DESTINATION -d returnJSON=true -d returnGeometries=false -d returnInstructions=false -d timeout=60000 -d nPaths=1 | ./jsawk "var total = 0; for (var i = 0; i < this.response.results.length; i++) { total += this.response.results[i].crossTime; } return total;"`

    EPOCH_NOW=`date +%s`

    let "WHEN_TO_LEAVE = EPOCH_TO_ARRIVE - ((60 * $MINS_BEFORE) + $TIME_TO_DRIVE)"
    let "TIME_LEFT = ($WHEN_TO_LEAVE - $EPOCH_NOW) / 60"

    if [[ $TIME_LEFT -le 0 ]]; then
        let "TIME_LATE = 0 - TIME_LEFT"
        LL=`echo $DESTINATION | sed -E 's/x%3A(.+)\+y%3A(.+)/\2,\1/'`
        curl -d "email=$BOXCAR_EMAIL" -d "notification[message]=Leave!+You+are+$TIME_LATE+minute/s+late+to+leave+to+$FORMATTED_2!" -d "notification[source_url]=waze://?ll=$LL" http://boxcar.io/devices/providers/$BOXCAR_API_KEY/notifications
        echo Leave! You are $TIME_LATE minute/s late to leave to $2!
        sleep 60
    else
        echo Not yet. You still have $TIME_LEFT minute/s left.

        if [[ $TIME_LEFT > 10 ]]; then
            let "SLEEP_TIME = $TIME_LEFT / 2 * 60"
            sleep $SLEEP_TIME
        else
            sleep 60
        fi
    fi
done
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s