Things used in this project

Hardware components

Story

TMI (Trimet Inspector)

We commute to work everyday, by walking, by bike but most often in this cloudy city of ours... we bus! Often when we're waiting for our regular bus and want a nice display for how long we have to wait. Or we might be getting ready in the morning and want to know how fast we should be moving to make to our stop in time.

We decided to make an API that provided convenient endpoints for multiple kinds of devices to use to display information on how long you have until the next bus, what the weather looks like outside, and (one day) alerts for route delays etc.

Into this API we integrated a customizable Pebble watchface (a watchface over an app to provide more convenience that looking at your phone would), and an Electric Imp LED display. The Pebble will display the time in minutes until your regular bus and the weather conditions. The Electric Imp will display different colors (green, yellow, red) based on the amount of time you have until you should be out of the door in the morning.

8 minutes til the next 15 at stop 4016, and cloudy outside

To extend this we made the stop-id and bus number configurable via the Pebble mobile app.

Extensions to this that we didn't have time for but started on were *things* like being able to have the Imp and Pebble __strongly__ suggest to bike or walk, by displaying `blue skies` and a biking gif and a blue color on the Imp. We'd also like to add images for the weather forecast.

Another direction we'd like to take this is being able to give you information about the nearest car2go, time until your cab via Curb or Uber arrives. We've already integrated location information into the Pebble aspect of project so extending the project in these ways is nearly trivial.

We wrote the API in Clojure on Heroku and the configuration app for the Pebble in ClojureScript.

Our configuration page is written in ClojureScript, a state-of-the-art, functional LISP that compiles to JavaScript.

Code

TMI-ELECTRIC-IMP-AGENT

JavaScript

locallatestWeather=null;localnextTime=-1;// Define the response handlerfunctionhandleWeather(responseTable){// Expects the responseTable to be pre-validated.localdata=http.jsondecode(responseTable.body);latestWeather=data.weather;}functionhandleTime(responseTable){// Expects the responseTable to be pre-validated.localdata=http.jsondecode(responseTable.body);nextTime=data.arrivals[0];}functionhandleResponse(responseTable){// Called when the imp receives a response from the remote serviceif(responseTable.statuscode==200){// Remote service has responded with 'OK' so decode// the response's body 'responseTable.body' and headers 'responseTable.headers'// Code omitted for clarity handleWeather(responseTable);handleTime(responseTable);server.log("latestWeather = "+latestWeather+", nextTime = "+nextTime);}else{// Log an errorserver.log("Error response: "+responseTable.statuscode)device.send("updateColor","orange");}}functionupdate(){server.log("updating!")// Set up outgoing request objectlocalrequest=http.get("http://hackthings-tmi.herokuapp.com/advice?stop=4016&bus=15",{});// Send the request asynchronously. This will not block the imp CPUrequest.sendasync(handleResponse);}functiongetColor(){if(nextTime<=2){return"red";}elseif(nextTime<=6){return"yellow";}elseif(nextTime<=12){return"green";}else{return"blue";}}functionupdateDevice(noop=null){device.send("updateColor",getColor());}functionclockTick(){// First, set a trigger to do the next tick in one minutes timeimp.wakeup(60.0,clockTick);// if the next arrival is in negative time, refreshif(nextTime<=0){update();}else{// otherwise decrement the timernextTime--;}updateDevice();}clockTick();device.on("updateMe",updateDevice);