Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //To do
- //Allows user to set bus#, route#, MaxWaitTime, MinTimeToCathcBus, Time to Check
- //Animations speed up and red in color as bus approaches
- //Format URL from parameters
- //Add a button to start the beacon for an hour outside the desired hours
- #include "neopixel/neopixel.h"
- #include "SparkTime/SparkTime.h"
- #include "rest_client.h"
- #include "jsmnSpark.h"
- #include "application.h"
- #include "math.h" //for breathing neopixel pattern
- #pragma SPARK_NO_PREPROCESSOR
- #define TOKEN_STRING(js, t, s) \
- (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \
- && strlen(s) == (t).end - (t).start)
- #define TOKEN_PRINT(t) \
- Serial.print(", type: "); Serial.print((t).type); Serial.print(" size: "); Serial.print((t).size); \
- Serial.print(" start: "); Serial.print((t).start); Serial.print(" end: "); Serial.println((t).end)
- /* IMPORTANT TO CHANGE THE NUMBER OF TOKENS TO MATCH YOUR DATA CLOSELY */
- #define NUM_TOKENS 150
- #define MAX_OBJ_SIZE 50
- #define HOSTNAME "api.pugetsound.onebusaway.org"
- //Neopixel related
- #define PIXEL_COUNT 8
- #define PIXEL_PIN D1
- #define PIXEL_TYPE WS2812B
- //Bus related
- //#define BusToCheck "73"
- int HoursToCheck[2] = {0,24};
- int MinTimeToCatchBus = 7;
- //String BusNum = "44";
- //String StopId = "1_67612";
- //String AccessToken = "XX"; //access token for onebusaway API
- //String MinutesBefore = "13";
- //String MinutesAfter = "15";
- //debugging related
- int attempt = 1;
- int led = D7;
- int BeaconRuns = 0;
- Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
- void StartVisualBeacon(uint16_t BusComingInMins);
- void CheckForBus();
- void ResetCore();
- RestClient client = RestClient(HOSTNAME);
- String response;
- void setup() {
- Serial.begin(9600); // Make sure serial terminal is closed before powering up Core
- pinMode(led, OUTPUT);
- long unsigned CurrentMillis = millis();
- // Open serial terminal and hit any key - halts execution - required to use serial on windows - Now Waits only a minute for key press
- while(!Serial.available() && millis()-CurrentMillis < 60000)
- {
- SPARK_WLAN_Loop();
- delay(1000);
- }
- //while(!Serial.available()) Spark.process(); // Open serial terminal and hit any key - halts execution - required to use serial on windows -
- Time.zone(-8); //SEA
- //initialize neopixels
- digitalWrite(led, HIGH);
- //Initialize neopixels
- strip.begin();
- strip.show();
- Serial.println("Starting in 3 secs..");
- delay(3000); //in case want to reflash, this would be the chance
- digitalWrite(led, LOW);
- }
- void loop() {
- //Check if the hour is when user wants to be notified
- if (Time.hour()>=HoursToCheck[0] && Time.hour()<=HoursToCheck[1]) {
- Serial.println("Good time to check for bus");
- Serial.print("Hour now: ");
- Serial.println(Time.hour());
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- Serial.print("Attempt this session: ");
- Serial.println(attempt);
- //check if Bus is coming
- CheckForBus();
- attempt=attempt+1;
- if (attempt>9) ResetCore(); //Spark has been a good boy, Reset every 10 minutes if no bus is coming
- }
- else
- {
- Serial.println("Not a good time to check for Bus. Get a cab");
- }
- Spark.process();
- delay(10000); //check for hour every 10 secs - change to sleep
- }
- void CheckForBus() {
- response = ""; // Clear the response String
- Serial.println("");
- Serial.println("Initializing GET request");
- Serial.println("Printing response string before the request");
- Serial.println(response);
- Serial.println("");
- jsmn_parser p;
- jsmntok_t tok[NUM_TOKENS];
- //pointers
- int i, r;
- char obj[MAX_OBJ_SIZE];
- //Token indices and names
- //indexes for tokens
- int PredictedIndex[2] = {26, 27}; //TokenName Index, TokenValue Index
- int RouteNameIndex[2] = {40, 41};
- int PredictedArrivalTimeIndex[2] = {30, 31};
- int ScheduledArrivalTimeIndex[2] = {44, 45};
- //char Predicted[MAX_OBJ_SIZE];
- char BusArrivalTimeString[MAX_OBJ_SIZE];
- //char BusArrivalTimeString_trunc[MAX_OBJ_SIZE];
- //double RouteName;
- double BusArrivalTime;
- int TimeToArrival;
- obj[0] = Serial.read(); // Flush the serial buffer to pause next time through
- // GET request
- //String url = String("/api/where/arrivals-and-departures-for-stop/" + StopId + ".json?key=" + AccessToken + "&minutesBefore=-" + MinutesBefore + "&minutesAfter=" + MinutesAfter + "&includeReferences=false");
- //Serial.println(url); //doesn't work as RESTClient library expect a const char* path
- //int statusCode = client.get(url, &response);
- int statusCode = client.get("/api/where/arrivals-and-departures-for-stop/1_29215.json?key=XX&minutesBefore=-12&minutesAfter=15", &response);
- //67612- bellevue
- //29215- seattle
- if(statusCode != 200) {
- Serial.print(F("Error code from server: "));
- Serial.println(statusCode);
- ResetCore(); //To bad, I think this is breaking the flow
- return;
- }
- Serial.print("Response body from server: ");
- Serial.println(response);
- Serial.println(" ");
- Serial.print("Response length is: ");
- Serial.print(response.length());
- Serial.println(" ");
- if (response.length() < 300 || response.length() > 2000) { //Quick and dirt way to check if only one bus is coming
- Serial.println("No bus is coming");
- Serial.println(" ");
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- digitalWrite(led, HIGH);
- delay(10000);
- digitalWrite(led, LOW);} //~50 secs
- return; //exit to loop and wait another 10 secs
- }
- //A bus is coming
- // Parse response from server
- jsmn_init(&p);
- r = jsmn_parse(&p, response.c_str(), tok, NUM_TOKENS);
- // Determine status code
- if (r == JSMN_SUCCESS) {
- Serial.println("Parsed successfully.");
- }
- else if(r == JSMN_ERROR_INVAL) {
- Serial.println("Bad token, JSON string is corrupted!");
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);} //~50 secs
- return;
- }
- else if(r == JSMN_ERROR_NOMEM) {
- Serial.println("Not enough tokens, JSON string is too large! Increase NUM_TOKENS.");
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);} //~50 secs
- return;
- }
- else if(r == JSMN_ERROR_PART) {
- Serial.println("JSON string is too short, expecting more JSON data!");
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);} //~50 secs
- return;
- }
- else {
- Serial.println("Parse failed! Unknown Error.");
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);} //~50 secs
- return;
- }
- // Check few tokens names to make sure the parsing worked correctly
- if ( TOKEN_STRING(response.c_str(), tok[PredictedIndex[0]], "predicted") ) {
- Serial.println("Predicted tokenName is correct");
- if ( TOKEN_STRING(response.c_str(), tok[PredictedArrivalTimeIndex[0]], "predictedArrivalTime") ) {
- Serial.println("PredictedArrivalTime tokenName is correct");
- Serial.print("Now checking for: ");
- Serial.println("44");
- //check for bus name
- if ( TOKEN_STRING(response.c_str(), tok[RouteNameIndex[1]], "44") || TOKEN_STRING(response.c_str(), tok[RouteNameIndex[1]], "44E")) {
- //strlcpy(Predicted, &response.c_str()[tok[PredictedIndex[2]].start], (tok[PredictedIndex[2]].end - tok[PredictedIndex[2]].start + 1));
- Serial.println("BusToCheck checks out");
- if ( TOKEN_STRING(response.c_str(), tok[PredictedIndex[1]], "true") ) {
- //Use predicted arrival time - truncate the trailing 0000 - otherwise it causes ovf (for both strtod and atof)
- strlcpy(BusArrivalTimeString, &response.c_str()[tok[PredictedArrivalTimeIndex[1]].start], (tok[PredictedArrivalTimeIndex[1]].end-3 - tok[PredictedArrivalTimeIndex[1]].start + 1));
- BusArrivalTime = strtod(BusArrivalTimeString, NULL);
- //BusArrivalTime=atof(BusArrivalTimeString);
- Serial.print("\nPrediction is true. BusArrivalTimeString: ");
- Serial.print(BusArrivalTimeString);
- Serial.print(" and BusArrivalTime: ");
- Serial.print(BusArrivalTime);
- }
- else {
- //Use scheuduled arrival time
- strlcpy(BusArrivalTimeString, &response.c_str()[tok[ScheduledArrivalTimeIndex[1]].start], (tok[ScheduledArrivalTimeIndex[1]].end-3 - tok[ScheduledArrivalTimeIndex[1]].start + 1));
- // Convert string to double, contains numerical value of milliseconds to arrival
- BusArrivalTime = strtod(BusArrivalTimeString, NULL);
- //BusArrivalTime=atof(BusArrivalTimeString);
- Serial.print("\nPrediction is false. BusArrivalTimeString: ");
- Serial.print(BusArrivalTimeString);
- Serial.print(" and BusArrivalTime: ");
- Serial.print(BusArrivalTime);
- }
- //calculate minutes to arrival
- TimeToArrival = (BusArrivalTime - Time.now())/60;
- Serial.print("\nYour bus is coming in ");
- Serial.print(TimeToArrival);
- Serial.println(" mins. Pack your bags");
- Spark.process();
- StartVisualBeacon(TimeToArrival); //CYAN
- Spark.process();
- } //bus is coming loop ends
- else {
- Serial.print("\nYour bus is not coming but ");
- //Provide the bus# thats incoming
- i=RouteNameIndex[1];
- strlcpy(obj, &response.c_str()[tok[i].start], (tok[i].end - tok[i].start + 1));
- Serial.print(obj); Serial.println(" is coming");
- //lay low for a minute
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);} //~50 secs
- return;
- } //some bus is coming loop ends
- }
- else {
- i=PredictedArrivalTimeIndex[1];
- Serial.print("\nToken:");
- Serial.print(i);
- Serial.print(" expected: predictedArrivalTime but instead is ");
- strlcpy(obj, &response.c_str()[tok[i].start], (tok[i].end - tok[i].start + 1));
- Serial.println(obj);
- //TOKEN_PRINT(tok[PredictedArrivalTimeIndex[1]]);
- Serial.println("TokenIndex error, please debug");}}
- else {
- i=PredictedIndex[1];
- Serial.print("\nToken:");
- Serial.print(i);
- Serial.print(" expected: predicted but instead is ");
- strlcpy(obj, &response.c_str()[tok[i].start], (tok[i].end - tok[i].start + 1));
- Serial.println(obj);
- //TOKEN_PRINT(tok[PredictedArrivalTimeIndex[1]]);
- Serial.println("TokenIndex error, please debug");}
- } //end of HourIsRight()
- void StartVisualBeacon(uint16_t BusComingInMins) {
- //Define colors here
- //START WITH CYAN
- uint8_t Rstart = 0;
- uint8_t Gstart = 255;
- uint8_t Bstart = 255;
- uint32_t c = strip.Color(Rstart,Gstart,Bstart); //Cyan
- //END WITH RED
- uint8_t Rend = 200; //2/3 of maximum red
- uint8_t Gend = 0;
- uint8_t Bend = 0;
- //temp variables
- uint8_t Rnew, Gnew, Bnew;
- //NumIterations for color transitions
- int n = 10000;
- Serial.println("Begining Visual Beacon");
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- float val;
- //uint16_t i,j;
- //unsigned long currentMillis;
- Serial.println("Begining Cyan animations");
- long unsigned CurrentMillis = millis(); //.
- for(uint16_t j=0;j<(BusComingInMins-MinTimeToCatchBus)*6000;j++){
- val = (exp(sin((millis()-CurrentMillis+3000)/2000.0*3.14)) - 0.36787944)*108.0; //Math here: http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 4 secs cycle, plotted in matlab
- //starting animations at sine argument 0 is ideal. Math says that number is 3000. Thats the reason for offset
- strip.setBrightness(val);
- for(uint16_t i=0; i<strip.numPixels(); i++) {
- strip.setPixelColor(i, c);
- strip.show();
- delay(1);}
- //Serial.println(j);
- }
- Serial.println(" Cyan animations end");
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- Serial.println("Begining color transitions");
- //slowly transition from Cyan to Red and glow RED at reduced brightness until a minute before the bus comes to the stop
- //idea is to notify the user that the bus is just leaving the stop
- for (uint16_t k = 0; k < n; k++) // larger values of 'n' will give a smoother/slower transition. takes about 1.5 mins
- {
- Rnew = Rstart + (Rend - Rstart) * k / n;
- Gnew = Gstart + (Gend - Gstart) * k / n;
- Bnew = Bstart + (Bend - Bstart) * k / n;
- // Set pixel color here.
- for(uint16_t i=0; i<strip.numPixels(); i++) {
- strip.setPixelColor(i, strip.Color(Rnew, Gnew, Bnew));
- strip.show();
- }
- delay(10);
- }
- Serial.println("Ending color transitions");
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- //Make the strip glow RED at reduced brightness until a minute before the bus comes to the stop to notify the user that the bus has just left
- Serial.println(" Red animations begin");
- for(uint16_t l=0;l<MinTimeToCatchBus-1;l++){
- for(uint16_t k=0;k<5;k++){
- Spark.process();
- delay(10000);}
- }
- Serial.println(" Red animations end");
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- //set strip to zero color on exit
- Rstart = 127;
- Rend=0;
- for(uint16_t j=0; j<n/10; j++) { //dont need that smooth here
- Rnew = Rstart + (Rend - Rstart) * j / n;
- // Set pixel color here.
- for(uint16_t i=0; i<strip.numPixels(); i++) {
- strip.setPixelColor(i, strip.Color(Rnew, Gnew, Bnew));
- strip.show();
- }
- delay(10);
- }
- //for good luck - make sure they are off
- for(uint16_t i=0; i<strip.numPixels(); i++) {
- strip.setPixelColor(i, 0,0,0);
- strip.setBrightness(0);
- strip.show();}
- Serial.println("Exiting animation loop");
- Serial.print("Minute now: ");
- Serial.println(Time.minute());
- //Update Beacons Runs
- BeaconRuns = BeaconRuns+1;
- //Core has been a good boy, call reset if this was second beacon run
- if (BeaconRuns>0) ResetCore();
- }
- void ResetCore(){
- Serial.print("Core reboot at: ");
- Serial.print(Time.hour());
- Serial.print(":");
- Serial.print(Time.minute());
- //Spark.sleep(SLEEP_MODE_DEEP, 30); //Deep sleep for 30 secs, resets on wakeup as well
- Serial.end();
- delay(3000); //lets the serial data out
- System.reset();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement