Waldemar Sakalus
Published © GPL3+

Particle traffic station powered by Bing maps

Glanceable traffic info

IntermediateFull instructions provided2,685
Particle traffic station powered by Bing maps

Things used in this project

Hardware components

Photon
Particle Photon
I actually used a Particle Core, Photon should work just fine
×1
SparkFun Serial Enabled 16x2 LCD - White on Black 3.3V
×1
LED (generic)
LED (generic)
used green, yellow and red (1 each)
×3
Resistor 220 ohm
Resistor 220 ohm
×1
Breadboard (generic)
Breadboard (generic)
×1
enclosure
×1

Story

Read more

Schematics

Breadboard view for the Traffic Station

Breadboard view for the Traffic Station

Code

Program

C/C++
// Waldemar Sakalus - Microsoft
// Example for hackster.io

int ledGreen = D0;
int ledYellow = D1;
int ledRed = D2;
float mildThreshold = 0.3;
float heavyThreshold = 0.6;
unsigned long elapsedTime = 0;

// called once on startup
void setup() {
  pinMode(ledGreen, OUTPUT);
  pinMode(ledYellow, OUTPUT);
  pinMode(ledRed, OUTPUT);
  
  // Initialize LCD display SparkFun Serial Enabled 16x2 LCD - White on Black 3.3V LCD-09067
  //position	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16
  //line 1	128	129	130	131	132	133	134	135	136	137	138	139	140	141	142	143
  //line 2	192	193	194	195	196	197	198	199	200	201	202	203	204	205	206	207
  
  Serial1.begin(9600);
  delay(500);
  Serial1.write(" "); // clear display
  Serial1.write(" ");
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(128);
  Serial1.write("Getting traffic");
  
  // Lets listen for the hook response
  Spark.subscribe("hook-response/traffic_hackster_io", gotTrafficData, MY_DEVICES);
  
  // Give visuyal cues something is happening and delay publishing for few seconds
  digitalWrite(ledGreen, LOW);
  digitalWrite(ledYellow, LOW);
  digitalWrite(ledRed, HIGH);
  delay(2000);
  digitalWrite(ledRed, LOW);
  digitalWrite(ledYellow, HIGH);
  delay(2000);
  digitalWrite(ledYellow, LOW);
  digitalWrite(ledGreen, HIGH);
  delay(2000);
  digitalWrite(ledGreen, LOW);
  delay(1000);
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(128);
  Serial1.write(" "); // clear display
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(192);
  Serial1.write(" "); // clear display
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(128);
  Serial1.write("Tot: Dly: ");
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(201);
  Serial1.write("Upd:");
}

void loop() {
  // Let's request the traffic, but no more than once every 60 seconds.
  // publish the event that will trigger our Webhook
  Spark.publish("traffic_hackster_io");
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(205);
  Serial1.write(" "); // clear rest display
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(205);
  Serial1.print( (millis() - elapsedTime) / 60000 );
  // and wait at least 60 seconds before doing it again
  delay(60000);
}

// This function will get called when traffic data comes in
void gotTrafficData(const char *name, const char *data) {
  //format of the data received "None~21.642~1120~1128~"
  //{{trafficCongestion}}~{{travelDistance}}~{{travelDuration}}~{{travelDurationTraffic}}~
  int prevIdx;
  int currIdx;
  float travelDurationMinutesFloat;
  float travelDurationTrafficMinutesFloat;
  String trafficCongestionDisplay;
  String str = String(data);
  
  // elapsedTime = 0;
  for (int i = 0; i < 4; i++) {
    if (i == 0) {
      prevIdx = 0;
      currIdx = str.indexOf("~");
      String trafficCongestion = str.substring(prevIdx + 1, currIdx);
      trafficCongestionDisplay = trafficCongestion;
    } else {
      prevIdx = currIdx;
      currIdx = str.indexOf("~", prevIdx + 1);
      if (i == 1) {
        String travelDistance = str.substring(prevIdx + 1, currIdx);
        //mile 1.60934 km
        //float travelDistanceMilesFloat = travelDistance.toFloat() / 1.60934;
        // String travelDistanceMiles( travelDistanceMilesFloat, 1);
      } else if (i == 2) {
        String travelDuration = str.substring(prevIdx + 1, currIdx);
        travelDurationMinutesFloat = travelDuration.toFloat() / 60;
        //String travelDurationMinutes( travelDurationMinutesFloat, 0);
      } else if (i == 3) {
        String travelDurationTraffic = str.substring(prevIdx + 1, currIdx);
        travelDurationTrafficMinutesFloat = travelDurationTraffic.toFloat() / 60;
        //String travelDurationTrafficMinutes( travelDurationTrafficMinutesFloat, 0);
      }
    }
  }
  
  String totalMinutes( travelDurationTrafficMinutesFloat, 0);
  float travelDelayFloat = travelDurationTrafficMinutesFloat / travelDurationMinutesFloat - 1;
  float travelDelayMinutesFloat = travelDurationTrafficMinutesFloat - travelDurationMinutesFloat;
  String delayMinutes( travelDelayMinutesFloat, 0);
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(132);
  Serial1.write(" "); // clear rest display
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(132);
  Serial1.print( totalMinutes );
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(141);
  Serial1.write(" "); // clear rest display
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(141);
  Serial1.print( delayMinutes );
  Serial1.write(254); // move cursor to beginning of first line
  Serial1.write(192);
  Serial1.write(" "); // clear rest display
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(192);
  Serial1.print( trafficCongestionDisplay );
  if (travelDelayFloat < mildThreshold) {
    digitalWrite(ledGreen, HIGH);
    digitalWrite(ledYellow, LOW);
    digitalWrite(ledRed, LOW);
  }
  else if (travelDelayFloat < heavyThreshold) {
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledYellow, HIGH);
    digitalWrite(ledRed, LOW);
  }
  else {
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledYellow, LOW);
    digitalWrite(ledRed, HIGH);
  }
  
  elapsedTime = millis();
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(205);
  Serial1.write(" "); // clear rest display
  Serial1.write(254); // move cursor to beginning of second line
  Serial1.write(205);
  Serial1.write("NOW");
}

Webhook

JSON
{
  "event": traffic_hackster_io",
  "event": traffic_hackster_io",
  "url": "http://bit.ly/1MSkCBe",
  "requestType": "POST",
  "headers": null,
  "query": null,
  "responseTemplate": "{{#resourceSets}}{{#resources}}{{trafficCongestion}}~{{travelDistance}}~{{travelDuration}}~{{travelDurationTraffic}}~{{/resources}}{{/resourceSets}}",
  "json": null,
  "auth": null,
  "mydevices": true
}

Dual destination variant

This is an updated software. It will rotate the display between 2 destinations. Two different webhooks needs to be created for this one.

Credits

Waldemar Sakalus

Waldemar Sakalus

4 projects • 18 followers

Comments

Add projectSign up / Login