Display real-time estimate of commute time between two locations based on traffic and historic data on a Character LCD using Raspberry Pi, Python 3 and Google Maps Distance Matrix API. If you have a LCD and a Raspberry Pi lying around or want to purchase one or if you are often late for work like me and want to have a traffic monitor then this project might be for you.

Hardware Requirements
- Raspberry Pi
- Character LCD
- Jumper wires
- Breadboard
- Potentiometer (If your LCD supports contrast adjustment)
Wiring
Essential wiring for writing data to LCD in four bit mode
Raspberry Pi | LCD |
---|---|
GND | VSS |
5V or 3.3V (Depends on LCD) | VDD |
GPIO 4 | RS |
GND | R/W |
GPIO 17 | E |
GPIO 25 | DB4 |
GPIO 24 | DB5 |
GPIO 23 | DB6 |
GPIO 18 | DB7 |
Depending upon LCD, you may have backlight.
Raspberry Pi | LCD |
---|---|
5V or 3.3V (Depends on LCD) | Backlight Anode (+ve) |
GND | Backlight Cathode (-ve) |
If your LCD supports changing of contrast, you can connect a potentiometer to adjust that.
Raspberry Pi | Potentiometer | LCD |
---|---|---|
5V or 3.3V (Depends on LCD) | +ve pin | |
GND | -ve pin | |
Data Pin | Contrast Pin (Usually 3rd pin on LCDs using Hitachi HD44780 LCD controller) |
Software Requirements
We are going to use Python programming language to make an Google Maps API call and then display the results to LCD.
Installing the dependencies
Adafruit Python CharLCD library
Get the LCD library
here and cd
to the downloaded folder and run the following command to install it.
sudo python3 setup.py install
Requests
Run the following command in terminal to download and install requests.
sudo pip3 install requests
Google Maps Distance Matric API
Run the following command in terminal to download and install the API.
sudo pip3 install -U googlemaps
Getting an API key to make API calls
Login to your google account and get the API key for your project. If you don't have an existing project, then you might have to create a new one here.
Python Code
Python 3 code for getting the commute time and displaying it on LCD
Importing the dependencies
import time
import Adafruit_CharLCD as LCD
import requests
Variables for making API call
Update the api_key variable with the key you got before.
api_key = 'YOUR_API_KEY'
base_url = 'https://maps.googleapis.com/maps/api/distancematrix/json?'
Origin and destination addresses
origin = 'Papakura,Auckland,New+Zealand'
destination = 'Penrose,Auckland,New+Zealand'
Variables for driving the LCD
Corresponding Raspberry Pi GPIO pins for register select, instruction and data registers on LCD. We will use these variables later to initialize the LCD.
lcd_rs = 4
lcd_en = 17
lcd_d4 = 25
lcd_d5 = 24
lcd_d6 = 23
lcd_d7 = 18
Size of the LCD, If you have a character LCD of 16x2, then modify the lcd_columns variable to 16 and lcd_rows to 2. Since, I used 20x4 LCD, I will use the following values.
lcd_columns = 20
lcd_rows = 4
Initialize the LCD
Create a lcd object by calling the constructor method defined in the Adafruit LCD library and pass in the required parameters. If your LCD supports backlight, then you could pass in an additional parameter of backlight = 1 or backlight = 0 to turn it on or off.
lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows)
Making the API call
We are going to structure the URL and then use python library requests to make a get request to API endpoint. To get a valid response you will also need to include additional parameters namely origins, destinations, departure time, traffic_model and API key in your request. Response message is then stored in variable and converted to JSON. In this example, I have passed in the result to display message. This method makes two requests - one to get best guessed commute time and other to get pessimistic time. Pessimistic time will be often more than the best guessed time.
def get_data():
try:
# Make request to get best guess duration between specified two points
r1 = requests.get(base_url+'origins={}&destinations={}&departure_time={}&traffic_model={}&key={}'.format(origin, destination, time_in_seconds_UTC(), 'best_guess', api_key))
r1= r1.json()['rows'][0]['elements'][0] # Convert the response to JSON
best_guess_duration = r1['duration_in_traffic']['text']
# Make request to get worst case duration between specified two points
r2 = requests.get(base_url+'origins={}&destinations={}&departure_time={}&traffic_model={}&key={}'.format(origin, destination, time_in_seconds_UTC(), 'pessimistic', api_key))
r2 = r2.json()['rows'][0]['elements'][0] # Convert the response to JSON
pessimistic_duration = r2['duration_in_traffic']['text']
display('Estimated Drive Time', 'BG: ' + best_guess_duration, 'PSMT: ' + pessimistic_duration, human_readable_time()) # Pass the results to display function
except requests.exceptions.RequestException as e:
# Print time when exception happened and exception meyyssage
print(time.strftime("%d-%m-%Y %H:%M:%S", time.localtime()))
print(e)
display('Error, check console', 'Trying again...') # Update LCD with error message
Also, I have wrapped the code in try and except block to catch if the request fails for whatever reason. If the exception happens, print function will print the time when it happened and reason in console and LCD will show Error, check console', 'Trying again...'. LCD will update with commute data again if the next request is successful.
The display function
Display function takes advantage of the message function provided by Adafruit LCD library. You can pass in upto four strings while calling it and it will display each string on a new line. lcd.clear() will clear any existing text on LCD and lcd.home() will bring the cursor to row 1 and column 1. For best results, you might want to limit the string length to maximum characters your LCD can display on each line. If you want to display multi-line message, then its best to use lcd.message()
def display(line1 = '', line2 = '', line3 = '', line4 = ''):
lcd.clear()
lcd.home()
lcd.message(line1 + '\n' + line2 + '\n' + line3 + '\n' + line4)
Get real time traffic data
So far, we have the code to get distance and duration but but we are not actually making a request. To get a response we have to call get_data() function and keep calling it every minute to get the updated duration based on traffic. I have wrapped this code in main() function
def main():
display('Loading...')
get_data() # Gets and displays data on LCD
time.sleep(60) # Wait for 1 minute
The following code will keep the program running once started and display Stopped on LCD when you stop it.
# Keep the program running and update LCD every 1 minute
while True:
try:
main()
finally:
display('Stopped')
Other helper functions
Helper functions are called in get_data() method.
# This piece of code returns the time in seconds in UTC which is passed to maps API as a value for departure_time
def time_in_seconds_UTC():
return int(round(time.time()))
#Following code returns a human readable date and time, this is printed on fourth line of LCD
def human_readable_time():
return time.strftime("%d %b %Y %I:%M %P", time.localtime())
Starting the app
Finally, we are at a point to start the program and get the real time traffic duration and distance on the LCD. You can get the source code here.
Download the zip file and extract it. Open up your command prompt or terminal and cd into the folder and run the following command.
python3 app.py
That's it. Thanks for reading.