Created
December 14, 2018 00:47
-
-
Save heaversm/cbcea2cfb7ffe0541baaac96d91e6a8c to your computer and use it in GitHub Desktop.
Getting the arrival API data for a specific stop on the Portland Trimet bus network, and lighting up an LED strip with the number of minutes before a bus arrives
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <WiFiClientSecure.h> | |
#include <TimeLib.h> | |
#include <NTPClient.h> | |
#include <WiFiUdp.h> | |
#include <Adafruit_NeoPixel.h> | |
//WIFI | |
const char* ssid = "[MY_SSID]"; | |
const char* password = "[MY_PASSWORD]"; | |
//const char* ssid = "Make + Think + Code"; | |
//const char* password = "codethinkmake"; | |
//API | |
const char* host = "developer.trimet.org"; | |
String url = "/ws/V1/arrivals/locIDs/5901/appID/[MY_APP_ID]"; | |
const int httpsPort = 443; | |
WiFiClientSecure client; | |
//TIME | |
#define NTP_OFFSET -8 * 60 * 60 //Portland is UTC - 8 | |
#define NTP_ADDRESS "pool.ntp.org" //Default NTP Address | |
#define NTP_INTERVAL 30 * 1000 // how often to update in miliseconds | |
WiFiUDP ntpUDP; | |
//NTPClient timeClient(ntpUDP,NTP_ADDRESS,NTP_OFFSET, NTP_INTERVAL); //use the custom ntp params | |
NTPClient timeClient(ntpUDP); //use the ntp defaults | |
//LIGHTS | |
#define PIN 15 | |
#define N_LEDS 9 | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800); | |
void lightsOnImmediate() { //turn lights on with no delay | |
for (uint16_t i = 0; i < strip.numPixels(); i++) { | |
strip.setPixelColor(i, strip.Color(255, 255, 255)); | |
strip.show(); | |
} | |
} | |
void lightsOffImmediate() { | |
for (uint16_t i = 0; i < strip.numPixels(); i++) { | |
strip.setPixelColor(i, strip.Color(0, 0, 0)); | |
strip.show(); | |
} | |
} | |
void activateLights(int numLights) { | |
Serial.println("activating lights"); | |
Serial.println(numLights); | |
for (uint16_t i = 0; i < numLights; i++) { | |
strip.setPixelColor(i, strip.Color(255, 255, 255)); | |
strip.show(); | |
} | |
} | |
//STATE | |
time_t timeEstimated; //when the next bus will come | |
time_t timeNow; //what time it is now | |
time_t timeDiff; //difference between now and estimated arrival | |
bool awaitingArrivals = true; | |
bool awaitingCurrentTime = true; | |
bool arrivalsRequested = false; | |
//CONFIG | |
int pollDelay = 30000; //time between each retrieval | |
int retryWifiDelay = 1000; | |
void setup() { | |
Serial.begin(115200); | |
strip.begin(); | |
//start time client to get real time | |
timeClient.begin(); //start the thing that tells us the current time | |
connectToWifi(); | |
} | |
void connectToWifi() { | |
//connect to wifi | |
Serial.print("connecting to "); | |
Serial.println(ssid); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { //WAITING FOR WIFI | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
void getArrivals() { | |
// Use WiFiClientSecure class to create TLS connection | |
Serial.print("connecting to "); | |
Serial.println(host); | |
if (!client.connect(host, httpsPort)) { | |
Serial.println("connection failed"); | |
delay(retryWifiDelay); | |
return; | |
} | |
//Query the API | |
Serial.print("requesting URL: "); | |
Serial.println(url); | |
client.print(String("GET ") + url + " HTTP/1.1\r\n" + | |
"Host: " + host + "\r\n" + | |
"User-Agent: BuildFailureDetectorESP8266\r\n" + | |
"Connection: close\r\n\r\n"); | |
Serial.println("request sent"); | |
while (client.connected()) { | |
String line = client.readStringUntil('\n'); | |
if (line == "\r") { | |
Serial.println("headers received"); | |
break; | |
} | |
} | |
String matchString = ""; | |
while (client.available()) { | |
String line = client.readStringUntil('\r'); | |
if (line.endsWith("</resultSet>")) { //this signals the end of the response from XML API | |
matchString = line; | |
} | |
} | |
Serial.println(matchString); //log result xml response from server | |
int lineEstimated = matchString.indexOf("estimated="); | |
if (lineEstimated == -1) { | |
Serial.println("NO ESTIMATED TIME!"); | |
turnSignOff(); | |
delay(retryWifiDelay); | |
return; | |
} | |
int lineStart = lineEstimated + 11; //exclude `estimated="` | |
int lineEnd = matchString.indexOf(" fullSign") - 4; //exclude ending zeroes and quote ( `000"` ) | |
String timeString = matchString.substring(lineStart, lineEnd); | |
int timeInt = timeString.toInt(); | |
Serial.println("estimated arrival timestamp: "); | |
Serial.println(timeInt); | |
timeEstimated = timeInt; //assign this to a timestamp | |
awaitingArrivals = false; | |
client.stop(); | |
} | |
void loop() { | |
if (awaitingArrivals) { | |
if (!arrivalsRequested) { | |
arrivalsRequested = true; | |
getArrivals(); | |
} | |
} else { | |
if (awaitingCurrentTime) { | |
awaitingCurrentTime = false; | |
getCurrentTime(); | |
} | |
} | |
} | |
void getCurrentTime() { | |
//get current time | |
timeClient.update(); | |
timeNow = timeClient.getEpochTime(); | |
Serial.println("timeclient epoch time: "); | |
Serial.println(timeNow); | |
//get epoch time to next bus arrival | |
timeDiff = timeEstimated - timeNow; | |
showDuration(timeDiff); | |
} | |
void showDuration(time_t duration) | |
{ | |
int numMinutes; | |
int numSeconds; | |
// prints the duration in days, hours, minutes and seconds | |
if (duration >= SECS_PER_DAY) { | |
Serial.print(duration / SECS_PER_DAY); | |
Serial.print(" day(s) "); | |
duration = duration % SECS_PER_DAY; | |
} | |
if (duration >= SECS_PER_HOUR) { | |
Serial.print(duration / SECS_PER_HOUR); | |
Serial.print(" hour(s) "); | |
duration = duration % SECS_PER_HOUR; | |
} | |
if (duration >= SECS_PER_MIN) { | |
numMinutes = duration / SECS_PER_MIN; | |
Serial.print(numMinutes); | |
Serial.print(" minute(s) "); | |
duration = duration % SECS_PER_MIN; | |
numSeconds = duration; | |
} | |
Serial.print(duration); | |
Serial.print(" second(s) "); | |
if (numMinutes < 1) { | |
turnSignOff(); | |
} else { | |
showNumber(numMinutes); | |
} | |
resetCycle(); | |
} | |
void turnSignOff() { | |
lightsOffImmediate(); | |
} | |
void showNumber(int numMinutes) { | |
activateLights(numMinutes); | |
} | |
void resetCycle() { | |
awaitingArrivals = true; | |
awaitingCurrentTime = true; | |
arrivalsRequested = false; | |
Serial.println("hold display..."); | |
delay(pollDelay); | |
Serial.println("poll again"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment