Monday, March 19, 2018

Designing and building the Mini Zapier display

In a previous blog post, I covered the details for a large-scale Illuminated Zapier display, which consisted of 248 tri-colored LEDs that were controlled by NodeJS on a Raspberry Pi.

One of my co-workers mentioned that it would be neat to have a smaller version of the display, which seemed like a great idea for a future project.

The theory/plan:

In May 2017, I started sketching out the possibilities:

When working out the math, it seemed that the quantity of LEDs per arm should be something like 5, 6, or 8.  When I searched around for the available options for LEDs, the best fit appeared to be the Adafruit DotStar 144 LED strip.  That would give me 6 LEDs per arm, and 8 arms per display, which is enough to build 3 full Zapier mini displays (6 x 8 x 3 = 144).

The next part was figuring out how "miniature" I could possibly make things.  Rather than building a custom Pi Hat (that would stack on top of the RasPi), I wanted something that would plug into the RasPi, without adding too much additional (stacked) height. 

The best approach was a Raspberry Pi Zero W, and then connecting it with a custom-designed board that would drive the LEDs. The dilemma was choosing stacked-headers, or right-angle connectors?

The advantage of stacked-headers is that the two rows of pins on the RasPi would line up with the pins on the custom board - whereas the right-angle headers causes things to connect up a little differently (outside rows versus inside rows).

In the end, I went with the (more complicated) option of using right-angle headers/connectors, so that the RasPi and custom board would lay flat together:

After each round of design and planning, I would print out the custom board's layout onto a sheet of paper, punch holes for all of the connectors, and lay out the components, in order to assess the spacing and physical dimensions.  This helped me avoid any pitfalls where the connectors would end up being "too close" and preventing things from being assembled correctly.

I used Autodesk's EAGLE software to design the schematic and layout of the custom board, along with lots of help and learning from some tutorials over at SparkFun. That resulted in the following layout:

When my paranoia was mostly-satisfied that I had all of the custom board's holes and traces/connections arranged correctly, I sent the design off to Osh Park for fabrication.  Their service sent back three copies of the completed board, which matched nicely with the quantity of LEDs that I had from the LED strip.

Some Assembly Required

When all of the parts arrived, the first step involved lots of time with a hacksaw, cutting the board apart, and also cutting up the connectors/headers into the specific sizes:

Then lots of long hours with a soldering iron, getting the connectors installed onto the RasPi and the custom board:

One of the unexpected and most difficult challenges was soldering the LED strip segments.  In my previous project, cutting the LED strip resulted in a full-circle of solder pads on each segment/strip.  Unfortunately, the high-density LED strip only provided a single solder pad in between each LED - thus when cutting apart the strip, I only had a half circle to use for soldering:

Eventually, I was able to solder (and re-solder) enough of the connections to get a few arms working correctly:

And then finally had the finished products:

Lessons Learned

The most difficult part of this project was the assembly/soldering of the LED strips onto the arms - and it's the most brittle part of the project.

When I started this project, there weren't any options available at the time.  Shortly after I started building this project, I discovered the Blinkt product/project, which would likely make the construction less tedious - but would require a larger board, with bigger connectors, and a 3 to 8 demultiplexer (74138 or 74238) along with some custom software/driver tweaks.  There's always a trade-off in these types of projects.

Additional Info

Thursday, October 29, 2015

Tracking workout data, using Zapier, MapMyFitness, and Google Sheets

A few months ago, I joined the Zapier team, and embarked on the mission of making computers perform more work (and thus, reduce the monotony inflicted on us humans).

I'm a huge fitness-data geek, and love all of the stats I can get from apps like MapMyFitness. When I finish a workout, I manually type in the info/stats from that workout over in my daily journal (currently, Evernote), which is time-consuming, and usually error-prone.

Seems like something that a computer could easily perform - and now that's entirely possible!

Using, it's pretty easy to connect up things so that your workout data from MapMyFitness can be fed into Everenote, Google Sheets, or hundreds of other possibilities.

Here's an example that connects things with Google Sheets, which makes it easy to see your workouts in a spreadsheet view.

If you don't already have an account over at Zapier, you can set one up (for free!). Once you're in, you can set up a Zap, which connects data from one source (like MapMyFitness) to a destination (like Google Sheets - which assumes you already have a Google/Gmail account. If not, it's probably time to give up the e-mail address you're using).

Let's set up a Google Sheet (spreadsheet) which will receive the workout data from MapMyFitness.

Go to and create a brand new Google Sheet:

In that sheet, setup some column headings, which indicate the fields/data that you will eventually connect up:

At the Zapier web site, go ahead and create a new Zap!

For the Trigger (data source), select MapMyFitness:

For the Action (data destination), select Google Sheets (again - this assumes that you have a Google/Gmail account, and have setup a spreadsheet like the one described earlier in this article):

Step #1 of your Zap should look something like this:

Zap Step #2: Connect your MapMyFitness account:

It will redirect you to the web site for MapMyFitness, where you have to grant access for Zapier to read your Workout data. This does not store any passwords - instead, MapMyFitness returns an "access token" that is used to access your workout information.

Zap Step #3: Connect your Google Sheets account. Same thing as the previous step - we don't store any passwords, just an "access token" provided on your behalf.

Zap Step #4: Filtering.
If you'd like to filter out things (like certain types of workouts), you can select the criteria here. Otherwise, just ignore this and continue to the next step.

Zap Setup #5: Mapping fields

This is the most important step - this is where you select your Google Spreadsheet, and Worksheet within that spreadsheet (since a spreadsheet may contain many worksheets)

Then, you'll need to select the incoming fields from MapMyFitness, and deposit the data into the correct columns.  For each field, use the button "Insert Fields", and select the correct entry. Like this:

Step #6:  Test it out! Go ahead and "Test Zap with this Sample". This will confirm that Zapier is able to receive Workout data from MapMyFitness. If you already have workout data present, you'll see the three most recent workout entries appear like this:

Step #7: Name the Zap, use something that will help you remember what it's doing, like "Track my workouts"

Go ahead and turn on the Zap, and then go for a walk/run/ride/swim or whatever you do with MapMyFitness. As you complete new workouts, they will accumulate within that spread sheet. Like this:

From there, the possibilities are endless - such as functions to display your total mileage for this year!

Sunday, October 11, 2015

It's a bomb^H^H^H^H clock!

A month ago, there was a huge amount of discussion over a clock that a kid brought to school, which had him arrested and suspended. I have a clock obsession, but only for really weird/geeky clocks. My current favorite is the Tix Clock available at ThinkGeek.

Since I'm usually a month (or more) behind on my blogging, here's my story.

Back in 1998, my dad happened to have a bunch of dual-color LEDs, consisting of Green and Red (and thus, Yellow when both colors were illuminated) that he no longer needed. When I counted them out, there were just over 60 LEDs present - which made me wonder if I could build a clock?

I had spent too much time building all kinds of fun things using various forms of the 8051 microcontroller, and since I had the EEPROM burner and UV eraser in my home lab, it was the best fit for the project.  (These days, I'd much rather use an Arduino or something).

Since a clock would require 60 individually addressable LEDs, along with two individually addressable colors, that equates to a lot more pins than what's available on the 8051.

Multiplexing to the rescue!

I'm a huge fan of multiplexers (and serial shift registers). In this case, I took the 60 LEDs and divided them into four quadrants. I could use two pins to select a quadrant, and then use four pins to select 16 different possible LEDs within that quadrant, using the 74154 4x16 demultiplexor. Throw in the two pins needed for the color selection, and I could drive all of the necessary data signals with eight little bits!

Since I had a few extra data pins available, I hooked up a few push buttons. Two are to set the minutes forward/backward, and two are to set the hours forward/backward. There's a fifth button, but I don't remember what it does.  Maybe some day I'll find the old assembler code I wrote for this project, and see if there's any mention of its purpose.


Any true hacker's project rarely comes in a "polished/presentable" case. So the next question was what kind of packaging to use for housing this project? I needed something round, and a large enough size to house a custom circuit board that I made. I thought of a frisbee, but they weren't deep enough for all of the wiring (done by hand - ugh!).  The next best candidate was an ol' fashioned pie tin!  After stuffing everything inside it, I used a piece of wire mesh to hold everything inside it.

Final result

Here's the "internal view".  The 8051 is the big 40-pin beast in the middle (with electrical tape covering the UV-EEPROM window). The push-buttons are just above the CPU. The 74154 is in the top-right corner. There's a bunch of 7407 inverters spread around the perimeter, which are used to drive the LEDs (common cathode/ground), along with a pair of transistors that supply the red/green anodes on the LEDs. Yes, I used to have a lot of spare time back then.

Action shot: The clock displaying the time 3:01:36 o'clock.

Semi-useless video clip:

I'm really thankful I never brought it into school for "show and tell". What's your favorite geeky clock? Leave a comment below!

Monday, July 13, 2015

Grandma's Marathon 2015

   After all of the grueling fun of running Twin Cities Marathon last fall, I decided to do another full marathon (uff-da!) 

  Here in Minnesota, everyone talks about Grandma's Marathon, so it seems to be the "premiere running event" of the upper Midwest. After having completed the run, it's nice and all, but it doesn't compare to the energy and entertainment of the Twin Cities Marathon. 

  Before the race started, the skies opened up and poured rain on top of the runners, as we waited in a car dealership parking lot. Some of the more "dry-minded" folks hit the pavement, and rolled beneath the various SUVs and "higher clearance" vehicles on the lot. Lots of folks (including me) pulled out the disposable trash bag, and threw it on as a temporary poncho.

  The rain lightened up during the first half of the run, and had pretty much stopped by mile 13. Unfortunately, everything was completely soaked inside and out. By mile 15, my right sock formed a soggy wrinkle beneath the knuckle of my big toe, and a blister ensued. I spent the later miles pushing harder with my left leg, in order to take the pressure off my right foot.

  All of that imbalanced running caught up to me around the 22 mile marker (and Lemon Drop hill), when my left quad started cramping up. I spent the last 4.2 miles alternating between a carefully balanced jogging stance, or just walking and massaging the cranky quad muscle, trying to coax a little more effort out of it.

  In the end, I managed to squeeze out a 4:10 finish, and a couple of free beers (whew!)

Wednesday, February 18, 2015

Running the Numbers

Over the last few years, I've participated in a few running events - which makes it difficult to mentally keep track them, and my completion times (fortunately, I have an Evernote Premium subscription to help with all of that). 

Some people consistently run the same event/distance every year, so they have no problem remembering their PRs. I like to try out new events/courses, and occasionally mix in a familiar event from a previous year - which further complicates the mental organization of stats.

Fortunately, most of these events have the finishers' information available via their websites, so with a bit of searching, I can eventually recall my stats from the past. 

But this brings up the question: Wouldn't it be great if there was a web interface to search all of those web interfaces simultaneously? 

Swiss Army Node

If you haven't already noticed from my previous blog posts, I love Node.js (and/or io.js -  hopefully they'll become the same thing again). Node.js is great at handling lots of input/output requests asynchronously, efficiently, without needing lots of code - especially if you use Promises to manage the application flow. 

Working from the back to the front

I prefer to start applications "from the back" - making sure that it's feasible to gather the necessary data, finding out what the limits are, and building an API that the front-end can use. 

I started with a list of popular running events in the area, and discovered that three of them used the mtec service to host the results for the past few years, which makes it super easy to get things started: 

Using Chrome Dev tools, I looked at the request being sent via their search form, and the markup that's returned (yeah, markup) - which can be a bit dangerous if it's not escaped correctly. For example, if a person has an apostrophe in their last name, this returned from their server:
<tr ...>  <td href="#">Firstname O'Lastname</td>  ... </tr>

Ideally, the apostrophe would be &#39; (but not mandatory). But this makes me wonder what would happen if I signed up for a race and entered my name as  <img src="..."/> (which reminds me of Bobby Tables).

Putting the pieces together

In the Node app, here's how I chose to implement the searching:
  • request and bluebird: From the back-end, I used the request package to create the HTTP/client connection to the race-results provider. Instead of using a callback function, I prefer to use Promises, so I wrapped the library using bluebird.promisify
  • cheerio: The race-results provider returns markup, but I'd prefer to use JSON for passing data. The cheerio package makes it super simple to use jQuery style selectors for parsing the text from the markup. 
  • bluebird again: In order to query lots of races simultaneously, I make a bunch of HTTP search/requests (which are now promises), and then use bluebird.all to wait until all of the searches have completed. Ideally, there should be a timeout promise in here so that if any of the individual search requests stalls, it won't delay the other searches.

Back to the Front

I've enjoyed using Angular UI Bootstrap on previous projects, so I wanted to branch out and try using Angular Material library. They share a lot of common concepts, such as the Bootstrap Grid versus the Material Design Layout Grid. It's nice to have resources that get a web interface up and working quickly and easily.

The UI is extremely simple, consisting of a single view that contains a few input fields, which are forwarded onto the back-end race-results providers.

To the Cloud

Given the straightforward/simple implementation of this app, it was easy to deploy into a Heroku Dyno. The app spends most of its time sleeping, so the initial request is always very slow (takes about 5 seconds for the Dyno to awaken).
Here's the deployed/running app:

Show me the Code!

The code is available on GitHub at:

Saturday, December 13, 2014

Handbell Hero!


It's like Guitar Hero, with 4 to 8 players, using a set of handbells from Groth Music. No musical background is necessary to play!


Every year, HelpSystems has an annual employee luncheon, which also involves some kind of game/entertainment thing that's led by a department.

Our department manager, Matt Bresnan, came up with the idea of putting together a Guitar Hero type of game, but using a set of handbells. I was asked to look into the feasibility of writing this app, and was given the MythBusters directive that If it's worth doing, it's worth overdoing!

Given the tools that I already know, Java was the easy choice because it has MIDI capabilities built into the language (which seems excessive, but extremely helpful). On the front-end, JavaFx was the right fit for this project.

Building and Running the game

The instructions for downloading, building, and running the game can be found at the GitHub repo:

The game works best on a Windows PC (using a 720p display or projector), and you'll need the Java 8 SDK (free download) installed (and in your PATH).

After a song completes, you'll need to press Alt-F4 to return to the menu screen (yeah, it's lame - I had it coded up to auto-close the window when the MIDI player/sequencer finished, but occasionally would receive an erroneous/premature "player stopped" event, that would close the game screen)


The most technically challenging part of this game is getting the "falling notes" to sync up with the music as it's played. This involves a bit of "lead-in" time ahead of the player, which means the UI has to understand MIDI tempo information.  For some reason, I couldn't get the math to work out, given the Sequence's Division Type, the Sequencer Tempo in MPQ, and the Sequencer Tempo in BPM.

I found numerous posts and Stack Overflow questions related to this topic, but the math never seemed to work out correctly. 

In the end, I just used a lame/dirty hack involving a properties file which specifies the number of "ticks per second" used by each of the MIDI files. Tip - the app defaults to 1700 ticks per second, so if your file happens to be close to that, there's no adjustment needed.

An even bigger limitation

This game currently ignores the MIDI Set Tempo events that occur within the MIDI Sequence.  There is code present to find/read those events, but since the math/calculations never worked out, I just stuck to fixed-tempo songs.

Adding your own MIDI files

If you'd like to use your own MIDI files (using just the key of C Major), you'll need to save them into the "midi" directory.  If you find that the UI starts at the wrong tempo (which is very likely), run the app using the command hh.bat log

Select your song, and let it play for a few seconds, then close the game (press Alt-F4 a few times).  In your Command Prompt window, you'll see stuff like this:

Ticks 4259.0 to 4341.0
Track entries 8 to 8

Ticks 4341.0 to 4430.0
Track entries 8 to 8

You'll need to determine how many MIDI Ticks there are in one second. Subtract two of the non-zero "PLAYER TICK" values, such as 2730 - 2641 = 89.  Then multiply that times 20, because the game refreshes the UI 20 times a second.  Thus, this song runs at 1780 MIDI ticks per second.

Edit the file resources\stupidHackTempo.props and add an entry for your song. The song's filenames are case sensitive, and you'll need to use the Unicode sequence "\u0020" for any spaces in the song's filename.

Rerun the game, select your song, and hopefully the UI will line up with your music.

Huge thanks to these people!

This was a team effort, and I'd like to give a shout out to these people:
  • Allen Fisher, for doing a superb job putting together the MIDI files.
  • Marshall Baltzell, for doing an amazing job with the two image files, especially on the Handbell Hero logo - he was dead-on with the appearance.
  • Matt Bresnan, for coming up with the initial game design, and giving me the opportunity to take some time to code up game.
  • The creator of the Nightmare Hero font, which adds to the visual effect of the game.
  • The audio effect on the selection menu, which adds to the audible effect of the game.
  • Apache FilenameUtils - they have libraries that make coding easier (and less cumbersome).

Got feedback?

If you love it, hate it, or have any questions, let me know! Either leave a comment below, or share with the entire world via Twitter @Panurgy

Tuesday, October 21, 2014

Training for a marathon - without running ragged

For the past few months, my "big project" was training for the Twin Cities Marathon (Oct 5th, 2014). I chose this "project" back in May, because I've completed several half-marathons over the last few years, and I wasn't getting faster - so I figured I may as well go farther.

Conventional wisdom assumes that this would involve a lot of running - most of the plans that you find on the Internet require four (or more) days of running every week, but now that I qualify as a "master runner", I knew that my knees wouldn't enjoy all of the pavement pounding required for a "proper training". 

Time to train smarter

From a geek's perspective, here's what it takes to be successful in a marathon:
  • Efficiency - get the most "mpg" out of your muscles
  • Endurance - the size of your "gas tank"
  • Determination - the mental fortitude to finish the job 

Essential equipment

  • Good pair of shoes, purchased from a running store, not a big-box sporting goods store. I personally have a slight pronation.
  • Lightweight moisture-wicking shirt and shorts (hopefully, your climate isn't like mine).
  • An HRM - I prefer the older Polar models - this is your "tachometer", and helps identify when you're hitting the "red line" and need to ease up.

A helpful item is a GPS enabled smartphone, and the means to take it on the run (arm band, fanny pack, whatever). I'm a huge addict of the site MapMyRun, with the ability to plan a safe/sane route (due to the dearth of running trails in my town), and then mapping it as I run it (I'm a huge stats/data geek). 

Getting started - finding the baseline

Since I was becoming "comfortable" running a half marathon, the first question was finding the max distance until I hit the wall. In late May, the Sunday morning forecast was a temperature in the low 50's and foggy - which is pretty much the perfect conditions, because fog means no wind. I managed to plod along at my usual pace for 18 miles, struggled for the next 2 miles, and then ended up "doing intervals" for the last 3 miles (yeah, that's a fancy way of saying "walk and run"). 

After that long run, my quads were complaining the most, so I needed a training plan that would build up that muscle group. The solution: hills and stairs!

Figuring out a training plan

The Twin Cities Marathon is a fairly flat course. I read a bunch of blogs and reviews from people who had run it, and most people agreed that the most difficult part was miles 20-23, which are uphill, coming up 200 feet from the river valley. I figured that hill training would probably be a good component of my training.

During the summer, my weeks pretty much went like this:
Sunday: Long run - either 10 miles (or more) of hills, or 13-16 miles of flatter terrain.
Monday: Relax
Tuesday: Intervals on a Stair machine
Wednesday: Swim laps (half mile or so)
Thursday: Variety day - outdoor run (4.5 miles) at a faster pace, or cardio exercise class, or more stairs/intervals.
Friday: Occasional indoor rock climbing (my favorite addiction)
Saturday: Relax

Peaking and Tapering

In the middle of September, I was three weeks away from the big event, and apparently that's the time to peak and start tapering. My Sunday morning run was 20 miles (and the first few miles were in darkness, sigh). At the end, the biggest problem was fueling and hydration - I had only packed two energy gels and a 20oz water bottle (with one refill at a park along the way).

The next weekend (two weeks out), I did a 13 mile run, and tried the Cliff Shot Blocks (chewy things), and discovered that they're really hard to chew while running. On the plus side, they have caffeine, which helps keep things moving.

Finally, one week away, ran a "big" run of 6 miles. Seemed almost "too short" compared to the weekly runs I had been doing.  A few days later, I was itching for a short run, so I did a 4.5 mile loop on mostly flat terrain, just to keep the familiar stride.

The big day

I always arrive at these events obscenely early, so that I can figure out where the starting corrals are, the gear/bag drop-off, and the most essential equipment: porta-potties! The temperature was in the upper 30's, which isn't quite warm enough for the basic "t-shirt and shorts" weather, so I threw on a wicking loose-fitting long-sleeved shirt.

The race was an amazing experience - many of the neighborhoods along the course make a huge production of cheering on the runners. With all of that energy being thrown at you, it's hard not to enjoy the event. One of the spectators teased me for smiling too much, claiming that I was "wasting precious endorphins" and that I should save them for the 20+ mile mark. I just smiled even more.

Just past the 15-mile mark, I had some amazing friends helping me out, and I peeled off the sweat-saturated shirt, and threw on a fresh (and dry!) wicking t-shirt, which was big improvement.

In the end, I completed the event in 4 hours and 5 minutes, which seemed like a pretty good finish for my first time. Huge thanks to all of volunteers that help make this event "run smoothly"!