Introduction: Traffic Report Check(NL) With Doormat

In this instructable I will describe how to build a doormat that will check traffic reports of Dutch highways. Once you step outside on your doormat and there is a traffic jam on your route, the mat will turn to a red color. When there is no traffic jam, the mat will turn green.

I will be working on a NodeMCU 1.0 (ESP0-12E Module). The code for this project could work on other devices as well (e.g. Arduino boards). This project is based upon a Dutch source for traffic reports, the ANWB.

What we need for this project:

- NodeMCU
- Jumper wires
- LEDlight or strip
- Analog sensor (Aluminiuim foil, Sponge)
- Wi-Fi connection
- Doormat

Steps we have to take:

1. Connect NodeMCu to Wi-Fi
2. Request data via HTTPS from ANWB.nl
3. Turn data into usable Information
4. Install the trigger
5. Design feedback

Step 1: Connect NodeMCU to Wi-Fi

This step will show how to do a successful HTTPSRequest to see whether the device is connected to the internet.

First, install the ESP8266 library in Arduino IDE.
Open from examples ESP8266 > HTTPSRequest.

Fill in your Wi-Fi credentials at the top of your code, as shown below:

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";

Upload the code to your device and check if the NodeMCU is connecting to the internet. The HTTPSRequest example uses Github as its default to get information from. When the HTTPSRequest succeeded, you receive the Github data in the serial monitor.

Step 2: Request Data From HTTPS From ANWB.nl

In this second step, you change the data source from the default to the source needed for this project: ANWB.nl.

At the top of your code, change char* host to www.anwb.nl (or another source you'd like to get your data from):

const char* host = "www.anwb.nl";
!! If you use another source, step 3 will be different from my code. Step 3 needs specific coding to retrieve usable information !!

Next, change the string url in the function setup to "/feeds/gethf", the path where the information is taken from:

String url = "/feeds/gethf";
!! If you use another source use the path to your source !!

When you upload the code you should get a response with all the data from www.anwb.nl/feeds/gethf. This code is saved into a string called line.

Step 3: Turn Data Into Usable Information

Until now, the code only ran when the NodeMCU was started or reset, because all the code is in the setup function. To set the trigger to run the code continously, you have to change the position of the code that runs the HTTPS request. Below the loop function, you add another function. I've called it void extractData:

extractData(){

}

Copy part of the code from the setup function into the extractData(). Start with the the following line until the end of the setup function:

if (!client.connect(host, httpsPort)) 

The code is now in your new function, so remove the copied code from the setup function.

Next, call the extractData function in the loop function and add some delay to give the nodeMCU time to rest:

void loop(){
extractData();
delay(30000); // this will be removed later when we have an analog sensor
}

Since the data you receive is stored in a string and only parts of this string are needed, you have to write a couple of for loops.

First, check all the positions of the word 'road'. After the word 'road', the name of the road will follow (A1, A2, etc.).

Before start writing the for loops, you have to declare some variables you are going to use:

int noOfPos = 0;
boolean hasRunOnce = false;
int from = 0;
int roadArray[20];

Now it's time to write some loops. I have written the for loops in the bottom of the extractData function. I tried to divide it into separate functions, but I couldn't get it to work.

For loop No. 1: find the positions of the word road in the string line:

  for(int i = 0; i < line.length(); i++){
    int pos = line.indexOf("road\":", from);
    roadArray[noOfPos] = pos;
    noOfPos += 1;
    from = pos + 1;
     if(hasRunOnce == true && pos == line.indexOf("road\":")){
      i = line.length();
     }
    hasRunOnce = true;
    }

Next, check what roads have a traffic jam, by using the positions of the for loop from above. The position of the name of the roads are always the same and start 7 characters and ending 10 characters after the word road.

Now we define the array nameOfRoadArray, which is going to be filled in the next for loop:

String nameOfRoadArray[20];

For loop No. 2: Find all the names of the roads with the input from for loop no. 1

for(int k = 0; k < 20; k++){
    int pos = roadArray[k];
    int positionOfRoadName = pos + 7;
    int endOfPositionOfRoadName = pos + 10;
    nameOfRoadArray[k] = line.substring(positionOfRoadName, endOfPositionOfRoadName);
  }

The array nameOfRoudArray should be filled with all the traffic jams signaled.

Next, you are going to check if your road is in the array of roads with a traffic jam. Print the nameOfRoadArray to get the roads in the data. Do this by adding the Serial.println(nameOfRoadArray[k]); into the 2nd for loop like:

for(int k = 0; k < 20; k++){
    int pos = roadArray[k];
    int positionOfRoadName = pos + 7;
    int endOfPositionOfRoadName = pos + 10;
    nameOfRoadArray[k] = line.substring(positionOfRoadName, endOfPositionOfRoadName);
    Serial.println(nameOfRoadArray[k]);
  }

If it's right you will see all the roads with a traffic jam in the Serial monitor.

Before writing the last For loop, you have to declare a boolean as a global variable. The boolean, called trafficJam is by default false and will change if the function extractData will return true for a traffic jam. The following code goes on top of the .ino file:

boolean trafficJam = false;

For loop No. 3: Check if the road, in this case A1, is in the list of traffic jams.

for(int l=0; l < 20; l++){<br>  if(nameOfRoadArray[l] == "A1\""){ //change A1 to road of your favor
    trafficJam = true;
  }

If you print trafficJam in the serial monitor, you know if there is a traffic jam on the A1 or not.

Put this code at the bottom of the extractData function:

Serial.println(trafficJam); //see if there is a traffic jam

With this information we are going to work further on the feedback of the system in step 5.

Step 4: Install the Trigger

Since we can now retrieve the data successfully from the source, it's time to build a sensor that will trigger the nodeMCU to run the function extractData. I chose to make an analog sensor out of my doormat. You could change the trigger by using another sensor.

Building the analog sensor.

I used 2 pieces of aluminium foil, two jumper wires and a sponge.

Drill a hole in the sponge, this is the place where the aluminium foils will make contact. Glue aluminium foil on both sides of the sponge. Connect jumper wires to the aluminium foil. Connect the jumper wires to the nodeMCU. One side to the A0-pin and the other to a V3-pin. Put the sponge under your doormat and you have just changed your doormat into a sensor. Awesome!

The code to read value from the sensor to see if somebody is standing on the doormat:

int sensorValue = analogRead(A0); 
if (sensorValue == 1024){
 extractData();
}

When the aluminium foil is making contact (when someone is standing on the mat), the sensorValue is 1024. This results in the function extractData() firing. And that's exactly what we want the system to do.

Step 5: Design Feedback

I used a LEDstrip to give feedback to the user. When there is a traffic jam, the light will color red. When the road is good to go, it will turn green. I used the adafruit neopixel library to control my LEDstrip.

Write this code in the top of your file to make sure the LEDstrip is defined:

#include <adafruit_neopixel.h><Adafruit_NeoPixel.h>
#define PIXEL_PIN     D5
#define PIXEL_COUNT   10
#define PIXEL_TYPE    NEO_GRB + NEO_KHZ800
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);<br></adafruit_neopixel.h>

Write the next code in the setup function:

//neopixel 
pixels.begin();
pixels.show();

And the following code in the loop function:

if (trafficJam == true){
    for(int i; i < PIXEL_COUNT; i++){
    pixels.setPixelColor(i, 255, 0, 0); // red
    pixels.show();
    delay(200);
    }
  } else{
    for(int i; i < PIXEL_COUNT; i++){
    pixels.setPixelColor(i, 0, 255, 0); // green
    pixels.show();
    delay(200);
    }

In the code above there is an if/else function. When the function extractData returns the presence of a traffic jam the LEDstrip will turn red. If not, the LEDstrip will turn green.

Step 6: Run the Code

If we run the complete code now, the sensor and light should work. When you stand on the doormat, the sensor will connect and the extractData function will run. When in the array of road names, the road we are looking for is present, the LEDstrip will turn red, signalling a traffic jam. If it's not in the array, the LEDstrip will turn green and you know you're good to go!

Have a safe journey and thanks for reading. I hope you found some inspiration or information. If you got some feedback, feel free to respond!