Tutorial: Train Departure Board with Pi, Python and an LCD

In this tutorial I explain how to build a train departures board using a Raspberry Pi, an I2C LCD, Python and the Tokyo Open Data for Public Transportation API.

Required Hardware

To get up and running you will need:

A Raspberry Pi

Any model with SDA, SCL, VCC and GND pins and a working network connection. I recommend the Pi Zero W or Pi Zero WH ( pre-soldered GPIO header).

An i2C LCD character display

I recommend a 20×4 display with a soldered i2C backpack like this

Required Software

Hook up the i2C display

Connect the display to the Pi’s GPIO pins like so:

Display SDA pin <------------> Pi GPIO 2 (SDA) pin
Display SCL pin <------------> Pi GPIO 3 (SCL) pin
Display 5V (VCC) pin <-------> Pi GPIO 5V pin
Display Ground (GND) pin <---> Pi GPIO Ground pin

Some displays can operate on the 3.3V pin. Check the labeling / instructions for your display before connecting and powering on.

To help you out, here is a helpful pinout diagram from https://www.raspberrypi.org

Enable i2C on the Pi

Boot up the Pi. Open a terminal window if necessary. To open Raspberry Pi Config CLI, type:

sudo raspi-config

Select 9 Advanced Options then P5 I2C to enable automatically loading the I2C service, then save, quit and reboot.

Download the i2C driver

To communicate with the LCD display via the i2C interface, you’ll need the I2C_LCD_driver.py script from Denis Pleic’s GitHub page.
Here is a direct link: I2C_LCD_driver.py

Download smbus

To allow Python to communicate via the i2C interface you’ll need to install the smbus package. This can be done with the following pip or pip3 command:

pip install smbus

pip (PyPi Python Package Index) is installed by default in Raspbian Desktop images (but not Raspbian Lite). If the command above fails because it is not installed, you can install it with apt like so:

sudo apt install python3-pip

Download my Departure Board Python script

Download my Python script that pulls data from the ODPT API, formats it for the LCD display and refreshes every 30 seconds.

GitHub Repo: https://github.com/ratticon/odpt-trainboard-pi-lcd
Direct link: odpt_train_board_pi_lcd.py

Save it to the same directory as the I2C_LCD_driver.py file you downloaded in the previous step.

I’ve included some default settings to get you started. Open odpt_train_board_pi_lcd.py and modify the following lines as needed:

# Config Variables ---------------------------------------
station = "Tokyu.Oimachi.Jiyugaoka"
direction = "Outbound"
lcd_width = 20
lcd_rows = 4
refresh_seconds = 30
overflow_animation = 'paging'

Here’s an explanation of how each variable works:

station – this string contains the railway operator, line, and station that we are requesting the timetable for. I plan on making a helper script so you can query the ODPT API and search for your desired station.

direction – this string should be either “Inbound” or “Outbound” (case-sensitive)

lcd_width – this integer describes how many characters can be displayed on one row of your LCD.

lcd_rows – this integer describes how many rows can be displayed on your LCD.

refresh_seconds – this integer describes how many seconds to wait between refreshing the timetable.

overflow_animation – I wrote two methods for animating destination names that are too long to fit on the LCD:

The "paging" method show whole segments of the destination name.
For example, "THISVERYLONGLOCATIONNAME" would be displayed as "THISVERYLO", "NGLOCATION", "AME       ".

The "scrolling" method scrolls long destination names from left to right, one character at a time. 

Export your ODPT API key

Once you have your API key, export it as an environment variable with the the export command, like so:


Run the timetable script

Run the following command to launch the timetable program:

python3 odpt_train_board_pi_lcd.py

I wrote the script for Python 3, so be careful to type python3 (not python) if 3 is not your default version.


You should now have a working LCD timetable, and see three columns on the display:

Column 1 will show EXP if the train is an Express train, or  Loc if it is a Local.

Column 2 will show the train’s departure time.

Column 3 will show (and scroll) the train’s final destination.

Bonus: Run it persistently in the background

If you are connecting to your Pi via SSH, you can run the script as a background process to free up the command line and keep it running after you disconnect. This can be achieved by using the nohup command like so:

nohup python3 odpt_train_board_pi_lcd.py &

You should see a process ID and a message that nohup is appending output to a file, something like this:

[1] 20918
user@pizero:~ $ nohup: ignoring input and appending output to 'nohup.out'

Hit Enter to resume using the command line.

If you want to kill the process, here are two methods:

1. Get the PID with ps and terminate it with kill :

Run the following command to get the PID (Process ID) of the script:

ps aux | grep -i odpt_train

This should return something like:

user       20918 90.9  4.1  29408 18300 ?        R    Apr30 106705:27 python3 odpt_train_board_pi_lcd.py

The number in the second column (20918 in the example above) is the PID. To send a terminate signal (15 – SIGTERM) to the process, run:

kill -15 <PID>

2. Use htop:

Run htop then hit F3 and type python.Ensure that the name of the script is highlighted, then hit F9 to open the kill menu. By default 15 SIGTERM will be highlighted. Hit Enter to send the terminate signal and kill the script, then F10 to quit.


Leave a Reply