guerillaClock, a low-cost countdown clock, provides bus arrival time by way of 16x32 RBG matrix backed by a Raspberry Pi Zero W.
It is a $100 solution to a $25,000 problem.
DetailsI heard about a local participatory budgeting vote wherein $1 million was allocated to several projects. Of those projects, bus countdown clocks were heavily favored - about a third of the voters picked the project.
But, I was surprised to learn that the intended clocks were approximately $25,000 a piece. That's quite the expense to convey updated bus route information - the affected community could only install 10 clocks with the appropriated funds.
So, I thought a low-cost Raspberry Pi Zero W powered solution could accomplish roughly the same thing at a fraction of the price.
The project utilizes a custom designed 3D printed enclosure to house a 16x32 RGB matrix and costs approximately $100. (The price could be reduced if a smaller lipo was used, or omitted entirely.)
The Raspberry Pi Zero W connects to a local wifi network and pulls bus arrival time and route details from the MTA Bus Time API. The 16x32 matrix displays the "next" bus' arrival time, for a selected bus stop.
The display is controlled with hzeller's great rpi-rgp-led-matrix project. The wiring.md was especially helpful in creating a Pi HAT, utilizing the Adafruit Perma Proto Bonnet.
Inside the enclosure the Raspberry Pi Zero W is powered by a Adafruit Power Boost 1000C which enables simultaneous charging capability for the LiPo, by way of a micro USB cable.
The project was written in Python and the code can be found on GitHub.
Build InstructionsStep 1-Setup Instructions (OSX)
To begin, the guerillaClock requires the basic set of Raspberry Pi components. And if this is the first time configuring a Raspberry Pi, then the Foundation's instructions are a recommended resource.
Prerequisites:
- Raspberry Pi + power
- Keyboard
- Monitor + HDMI cable
- SD Card
- Wifi access
- NYC MTA API key (Requires registration)
The overall steps, from Raspbian installation to `git clone`, are listed below. While the steps may be condensed, they are the basic steps required to bring guerillaClock online.
- Download and install Etcher to "burn" the Raspbian OS to the SD card
- Download Raspbian (Stretch Lite), the official OS for Raspberry Pi's, from raspberrypi.org
- Open Etcher and select the downloaded copy of Raspbian, the SD card (if not automatically pre-selected), and click Flash
- Power-on the Raspberry Pi with the newly flashed SD card
- Login with the default credentials (username: pi / password: raspberry)
Step 2-Configure the Raspberry Pi
Type sudo raspi-config and run through the following configuration steps:
Disable audio (Explanation)
- Type
sudo nano /boot/config.txt
- Change the line (usually the last in the file) "dtparam=audio=on" to "dtparam=audio=off"
- Change User Password (this will be a Wifi enabled device)
- Network Options (select a unique hostname and enter your Wifi network details)
- Boot Options (the console requiring user login is recommended)
- Localisation Options (change the timezone and keyboard layout to your locale)
- Interface Options (SSH is recommended to allow remote administration)
- Advanced Options (Expand File system is net necessary but recommended)
- Update
- Type sudo apt-get update and sudo apt-get upgrade to pre-installed software is up to date
- Type sudo apt-get install python-pip to install Pip, the Python package manager
- Reboot
Step 3-Install guerillaClock
Type nano config.ini and enter the following to create the config file
[main]
key = <your MTA API key>
stopID = <desired bus stop code>
- Update apt's package list by typing sudo apt-get update
- Type sudo apt-get install git-core to install Git
- Type git clone https://github.com/klinstifen/guerillaClock
- Type cd guerillaClock to enter the guerillaClock subdirectory
Step 4-Install the Required Python Packages
Type the following:
sudo pip install requests
sudo pip install python-dateutil
sudo pip install pytz
Step 5-Install guerillaClock's submodule
From within the guerillaClock subdirectory perform the following:
Type the following to install Python support (More information)
sudo apt-get install python2.7-dev python-pillow -y
make build-python
sudo make install-python
- Type git submodule init and git submodule update to install the rpi-rgb-led-matrix submodule
- Type cd rpi-rgb-led-matrix to enter the submodule subdirectory
Step 6-Configure guerillaClock to Run at Boot
Add the following above the line that says "exit 0":
#guerillaClock auto-start
cd /home/pi/guerillaClock && sudo python guerillaClock.py
- Type
sudo nano /etc/rc.local
More InformationThe results of each MTA Bus Time query are written to the guerillaClock.log. This file can be useful for troubleshooting purposes or to run guerillaClock in a headless configuration.
While guerillaClock is running, perform the following to monitor the log:
- Type cd guerillaClock (if not already within the guerillaClock subdirectory)
- Type
tail -f guerillaClock.log
The continuous output will list all the buses enroute, on layover, or at the terminal. The "next bus" is found by simply comparing the arrival times. The bus with the earliest arrival time is selected as the "next bus". And the bus line along with the estimated arrival time are displayed on the matrix.
If you encounter any errors, make sure you are running the latest version of guerillaClock by typing git pull from within the guerillaClock subdirectory.
Low Battery DetectionAfter a few unexpected shutdowns, due to low battery power, that resulted in SD card corruption (specifically Git cache corruption) I decided to take advantage of the LBO pin on the PowerBoost 1000c.
The LBO pin will go to 0V when the battery voltage drops below 3.2V. We can utilize a GPIO pin on the Raspberry Pi Zero W to monitor the LBO pin state and then initiate a system shutdown when the LBO pin goes low.
I selected GPIO pin 21 simply because it was at the end of the bonnet and out of the way.
Adding a male pin to the PowerBoost 1000c and a female jumper cable to the bonnet allows for easy disassembly if components need to be replaced.
To configure pin 21, we need but a few lines of code at the beginning of the guerillaClock.py script
#LBO shutdown
PINPIN = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
And finally, at the end of the main loop we check the current state of the LBO pin and shutdown the system if necessary.
#Check for low power
if not GPIO.input(PIN):
logger.debug("Low Battery Power Detected. Shutting down...")
GCD.off()
os.system("sudo shutdown -h now")
Power ConsumptionInitially, guerillaClock was to incorporate a solar panel for it's primary power source. As such it would need a backup battery, for cloudy days, so the case was designed around a 6600 mAh LiPo battery that was on hand.
To determine the power draw, a USB Charge Doctor was put in line and it showed voltage and amperage usage.
Calculating off the peak amperage, which interestingly is when the display is static, we can determine the approximate uptime.
Using some simplistic napkin-math, the LiPo's 6600mAh capacity / peak 360mA draw, we can anticipate the guerillaClock staying online for over 18 hours.
When not displaying a message the guerillaClock draws far less power. So, uptime could be improved by increasing the interval between arrival time calculations and display or by adding a physical button for on-demand only inquiries which could be considerably less frequent.
To make guerillaClock more mobile and versatile, additional wireless networks can be added beyond that which is configured within sudo raspi-config.
Add Additional Wireless Networks
- Type
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
- Look within the wpa_supplicant.conf file for a "network" section that looks like this:
network={
ssid="SSID_added_during_raspi-config"
psk="password_for_SSID"
}
- Add additional "network" sections for each wireless network to which guerillaClock will connect
network={
ssid="SSID_added_during_raspi-config"
psk="password_for_SSID"
}
network={
ssid="freewifi"
psk="topsecretpass"
}
network={
ssid="myHotSpot"
psk="passwordDefintedByHotSpot"
}
Comments