Skip to content

Instantly share code, notes, and snippets.

@heaversm
Created December 14, 2018 00:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heaversm/cbcea2cfb7ffe0541baaac96d91e6a8c to your computer and use it in GitHub Desktop.
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
#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