Ken (Chanoch) Bloom's Blog

30th January 2009

`bus' command for the CTA Bus tracker

So the CTA finally brought the bus tracker to busses running through my neighborhood. It gives you a nice Google map showing you where busses currently are on the route, and a separate web interface telling you how long before a bus reaches a given spot. Nice, but I don't want to open a web browser for all of that. (PACE has actually had my busses for a while.)

Enter the bus command:

#!/usr/bin/env ruby
require "yaml"
require "cgi"
require "open-uri"
require "time"

Location=Struct.new(:name,:lines)
CTA=Struct.new(:line,:dir,:stop,:id) do
  def url
    "http://www.ctabustracker.com/bustime/wireless/html/eta.jsp?route=%s&direction=%s&stop=%s&id=%d" %
      [self.line, CGI.escape(self.dir), CGI.escape(self.stop), self.id]
  end
  def times
    html=open(self.url){|f| f.read}
    mins=html.scan(%r{<b>(\d+).*MIN</b>}).flatten.map{|x| x.to_i}
    times=mins.map{|x| Time.now+x*60}
    mins.zip(times).map{|m,t| "#{t.hm} (#{m}m)"}.join(", ")
  end
  def description
    "%s %s (%s): %s" % [self.line, self.stop, self.dir, self.times]
  end
end

PACE=Struct.new(:line,:dir,:stop,:name) do
  def url
    "http://gis.pacebus.com/webwatch/ada.aspx?r=%d&d=%d&s=%d" %
      [self.line, self.dir, self.stop]
  end
  def times
    html=open(self.url){|f| f.read}
    times=html.scan(%r{>(\d+:\d+ [AP]\.M\.)}).flatten.map{|x| Time.parse(x)}
    mins=times.map{|x| ((x-Time.now)/60).to_i }
    mins.zip(times).map{|m,t| "#{t.hm} (#{m}m)"}.join(", ")
  end
  def description
    "#{self.name}: #{self.times}"
  end
end

class Time
  def hm
    strftime "%H:%M"
  end
end

locations=YAML.load_file("#{ENV['HOME']}/.bus.yaml")

locations.each do |location|
  puts location.name
  location.lines.each do |line|
    puts "  #{line.description}"
  end
end

And my ~/.bus.yaml

--- 
- !ruby/struct:Location 
  name: Home
  lines: 
  - !ruby/struct:CTA 
    line: 96
    dir: East Bound
    stop: Lunt & California
    id: 12043
  - !ruby/struct:CTA 
    line: 96
    dir: West Bound
    stop: Lunt & California
    id: 12077
  - !ruby/struct:CTA 
    line: 93
    dir: North Bound
    stop: California & Lunt
    id: 11915
  - !ruby/struct:CTA 
    line: 93
    dir: South Bound
    stop: California & Lunt
    id: 11871
  - !ruby/struct:CTA
    line: 49B
    dir: South Bound
    stop: Western & Lunt
    id: 1698
  - !ruby/struct:PACE
    line: 290
    dir: 1
    stop: 22090
    name: 290 Touhy & California (East Bound)

The secret codes (id for the CTA, and stop and dir for PACE) need to be filled in by visitng the bus you're interested in on the bus tracker first. For PACE, name is the name of the line --- since most of the site's inner workings are through secret codes, you need to provide a human-readable name yourself.

Now I can just run the bus command and see all of the nearby busses at a glance:

Home
  96 Lunt & California (East Bound): 14:46 (16m)
  96 Lunt & California (West Bound): 14:36 (6m), 14:54 (24m)
  93 California & Lunt (North Bound): 14:39 (9m), 14:51 (21m)
  93 California & Lunt (South Bound): 14:33 (3m), 14:55 (25m)
  49B Western & Lunt (South Bound): 14:37 (7m), 14:48 (18m), 14:58 (28m)
  290 Touhy & California (East Bound): 14:33 (2m), 14:44 (13m), 14:50 (19m)

Whoops. Here comes by #93 now. Better get going.

Permalink | linux.
My Website Archives

Tags