If you enjoyed this post, follow me on Twitter: @mikemetral
tl;dr —A mini project to recreate a home grown sports ticker which shows game information on an LED sign. Challenges: I had to find sporting stats, port code, and fight matrices composed of binary data to display information on an LED sign.
If you’d like to contact or follow me, I’m on Twitter: @mikemetral
- Technical Introduction
- Technical Meat
- Lessons Learned
I have a good friend named Eric. Eric is the definition of a sports fanatic. His love for sports goes so deep, that he has completely revamped his living room into a mini sports bar equipped with 5 TV’s that are constantly broadcasting a multitude of games across many sports leagues. His knowledge of sports is even more impressive than his setup — we once tested it by having him run through all of the NCAA March Madness champions from memory since 1979 and he only got stumped on 2 of them, earning him the nickname “The Sports Almanac.”
Here is what watching March Madness 2014 was like for us a couple weeks back. Needless to say, we watch every major sporting event at his place.
It was at this viewing party that we joked about the fact that the only missing piece from Eric’s “man wall” was a sports ticker giving us the latest game information, and hence, an idea was born.
So the next day, I asked myself “how hard can building a sports ticker really be?” I knew that at the very least I wanted a few key pieces:
- “Free” sporting information for the lowest barriers to entry in this project. This was an adventure in of itself best described in a programmatic sports stat blog post.
- An LED sign for the novelty of displaying the game information.
- And a Raspberry Pi for ultimate portability, minimal occupancy of space in a living room, and bonus brownie points in the homebrew / hacktivist community.
After perusing Google, I came across an interesting blog: SF Muni LED Sign at Home with Raspberry Pi — Bingo! Just what I was looking for. This blog described how one guy’s need for instant SF Muni information in his home led him to work through the pain points of writing to an LED sign and ultimately, open sourcing his code. There was just one “problem” for me in all of this, his code was all written in Ruby — I’m a Python guy. If you aren’t familiar with this proverbial coding war, feel free to start here.
Once I achieved the collection of the sporting stats by tweaking the Python script provided by the blog post, I shifted focus to writing to the LED sign. The collection of code for the SF Muni blog that deals with the LED sign is located here: https://github.com/pshved/muni-led-sign/tree/master/client.
It was in this ‘client’ directory that I spent the bulk of my time as I ported the Ruby code over to Python. The process of porting code is always an interesting one because you can never escape the wrath of understanding someone else’s rhyme or reason for why they decided to write a line of code.
Nevertheless, his code was great and it was exactly what I needed, so I started from the most logical step: pinning down the hierarchy of the code and how they interrelate to one another so that I can begin to port it.
SF Muni Led Sign Code Structure
- lowlevel.pl — Perl wrapper for Perl API interaction with the LED sign made available via the CPAN module: Device::MiniLED. Interestingly enough, this wrapper also accepts data to display more than one-line of text (as long as you format the data matrix appropriately before sending it to the sign — we’ll get to this later), a feature which does not come by default with the sign. SF Muni blog states:
Another reason why I wrote this API [wrapper] was that the sign does not support two-line text in its built-in text renderer. The API allows you to supply a [single] line of text, and the sign will happily render it, and even add some effects, but I wanted two lines in a smaller font instead. [The] API doesn’t have a “render image” function, but the sign allows you to create your own font glyphs, and insert them into text. The obvious idea of printing one 16x96 “symbol” worked. The wrapper does exactly this.
*Of note, the LED sign used both by myself and the SF Muni blogger (Pavel) is comprised of a 16x96 grid of LED’s.
- font/*.simpleglyphs — Collection of custom font glyphs that allows for the composition of individual ASCII characters using binary data to turn on / off a specific LED. Each character to binary data mapping is at most 8 columns long (which includes 1 column of LEDs above the character to be turned off, for spacing and aesthetic reasons) and 5 rows wide — thus, enabling a smaller font to allow for the display of 2 lines of text versus 1 line capable by default in the API.
- lib/simplefont.rb — Loads the custom font glyphs from font/*.simpleglyphs and renders the multiline text. It achieves the rendering by creating a single 16x96 matrix comprised of concatenated character glyphs for each character in the supplied strings for each of the top and bottom line of the LED sign.
- lib/sign.rb — Retrieves the rendering of the strings from lib/simplefont.rb and supplies it to lowlevel.pl API wrapper to write out to the sign.
Python Port of SF Muni “client” directory
I went ahead and ported the code which writes to the LED sign from Ruby to Python. The project has an entry point in client.py and a quick test.py script is available to get you bootstrapped.
Scores (aka ‘Ticker’) Project
This is my full sports ticker project which utilizes the Python port led_sign as a submodule.
The flow of the project is:
- Pull the sports info
- Store it in a database
- Render the stats into a 16x96 matrix
- Push the rendering to the LED sign
The layout of the project is outlined in the following main files:
- get_scores.py: Pulls the latest sports stats across the leagues I care to have and stores it in a MySQL database via SQLAlchemy. Storing it in a database is done to allow the displaying of information to be smoother
- display_scores.py: Works with the led_sign project to retrieve the information from the database and display it on the sign
- main.py: Overarching process that loops through get_scores.py & display_scores.py for a seamless looping of the ticker. This process is controlled via the Supervisord control system.
- install.sh: Bash script that performs the setup & configuration of the project specifically for a Raspberry Pi running on the latest Raspbian OS image (Release date: 2014-01-07)
- Ruby is interesting. I actually gave Ruby a fair chance way back when the Ruby on Rails Tutorial was posted and haven’t really touched it since. It was nice to refresh my memory on it and in porting my code to Python, I was really forced to figure out how Ruby operates.
- After going through the formation of a 16x96 matrix to render text for the sign, I have a new found appreciation for font glyphs, rendering engines and all things graphical. Really, this stuff can be hard and we take it for granted.
- It’s important to set a deadline with side projects — I gave myself 1 week. It really forces you to get your priorities inline.
- It’s important to have people to demo a project to & explain the process as well as the complexities you encountered. I debuted the ticker at my buddy’s place to a group of friends who happened to be over for another viewing party, this time it was the finale of the 2014 Masters Tournament — seriously, we watch too many sporting events at his place. P.S. they loved the ticker ☺
- Lastly, it’s important to blog about side projects as it helps to “close the chapter” on them, allows you to revisit the near-term struggles and achievements you faced, and inform others interested in the same topics.
If you’d like to contact or follow me you can reach me on Twitter: @mikemetral