For this week, I remade the lcd board from last week with a better lcd and hooked it up to the web. Besides the LCD, I changed routing on the board to put the wifi module on the non copper side which create a more mechanically sound board.
Initially, I was having contrast adjustment problems. The contrast at VO set to 1/100th of 5V but that seems to make everything fade out.
Making it closer to 5V didn't help either. In the end, I hooked up a variable resistor to V0 to adjust the contrast. It is very finicky and LCD dependent so I would suggest others do the same, ie. go the adjustable resistor route rather than hard code it in.
Now to getting the bus times.
Boston's public transit system, MBTA, has a REST API for querying bus arrival predictions.
Details on the API here:
http://realtime.mbta.com/portal
Here are some example calls:
http://realtime.mbta.com/developer/api/v2/routes?api_key=wX9NwuHnZU2ToO7GmGR9uw&format=json
given a route_id (from the last query), you find the stops
So for instance a stop I am interested in is:
{"stop_order":"13", "stop_id":"75", "stop_name":"84 Massachusetts Ave", "parent_station":"", "parent_station_name":"", "stop_lat":"42.35894", "stop_lon":"-71.093628" },
With this you get the predicted arrivals for a stop: http://realtime.mbta.com/developer/api/v2/predictionsbystop?api_key=wX9NwuHnZU2ToO7GmGR9uw&stop=75&format=json
{"stop_id":"75", "stop_name":"84 Massachusetts Ave", "mode": [ {"route_type":"3", "mode_name":"Bus", "route": [ {"route_id":"01", "route_name":"1", "direction": [ {"direction_id":"1", "direction_name":"Inbound", "trip": [ {"trip_id":"24538170", "trip_name":"10:01 pm from Massachusetts Ave @ Holyoke St to Dudley Station", "trip_headsign":"Dudley Station via Mass. Ave.", "sch_arr_dt":"1417403640", "sch_dep_dt":"1417403640", "pre_dt":"1417403640", "pre_away":"958", "vehicle":{"vehicle_id":"y2146","vehicle_lat":"42.3730506896973","vehicle_lon":"-71.1176147460938","vehicle_timestamp":"1417402627"} }, {"trip_id":"24538171", "trip_name":"10:19 pm from Massachusetts Ave @ Holyoke St to Dudley Station", "trip_headsign":"Dudley Station via Mass. Ave.", "sch_arr_dt":"1417404720", "sch_dep_dt":"1417404720", "pre_dt":"1417404720", "pre_away":"2038" } ] } ] } ] } ], "alert_headers":[] }
In summary, a bunch of nested stuff with the predicted arrival (pre_away
) buried in there. This data structure amounted to about 964 bytes. Too big for the atmega to process. Particularly for complex stops. So what the job called for was a web proxy that will simplify the api data into something more fit for the LCD or the tiny processing power of the avrs.
I used Google's AppEngine to write a python server that scraped MBTA and converted the json response to something simpler.
In main.py
from google.appengine.api import memcache from flask import Flask import mbta @app.route('/stop/<stop_id>') # simple url parsing def stop(stop_id): assert stop_id == '91' or stop_id == '93' # minimize abuse by internet data = memcache.get('stop:%s' % stop_id) if data is not None: return 'C' + data # return cached data else: data = mbta.text_for_stop_id(stop_id) # fetch data from mbta's api. format. memcache.add('stop:%s' % stop_id, data, 30) # cache for 30s return data
In mbta.py, here is the meat of the program:
import urllib2 import json def api2_url(request, **kwargs): params = kwargs.keys() url = '%s%s?api_key=%s&%s=%s&format=json' % (URL_BASE, request, API_KEY, params[0], kwargs[params[\ 0]]); return url def get_predictions_by_stop(stop_id): url = api2_url('predictionsbystop', stop=stop_id) try: result = urllib2.urlopen(url) return result.read() except urllib2.URLError, e: return None def text_for_stop_id(stop_id): json_str = get_predictions_by_stop(stop_id) if json_str is None: return '%s Error' % server_time() bus_times = parse_bus_arrival_times(json_str) # basically pretty prints that json return server_time() + '\n'.join(bus_times)
Configuration file for appengine. Very simple:
application: busview version: 1 runtime: python27 api_version: 1 threadsafe: yes module: default handlers: - url: .* script: main.app
in the directory
ubuntu:appengine$ dev_appserver.py .
ubuntu:appengine$ appcfg.py -A verdant-cable-780 update app
going to: http://verdant-cable-780.appspot.com/stop/75 gives me this:
C39 01 11m,29m
server_time, bus-direction and arrival times.
As I keep the board plugged in, I can see the qps on appengine's dashboard:
The esp8266 and avr communication is pretty brittle on the timing and took a bit of fussing around to get it right. I based my code off the ITEADLIB_Arduino_ESP8266 library.