How Place Matrix Works

or "How I learned to stop worrying and love staying up all night web programming again"

I've finally had some time to write up a bit more of a technical description of how Place Matrix works, following my introduction a few months ago.

I had a great time building this project because it was such an opportunity to learn about things with which I don't normally spend a lot of time tinkering. While I spend my days working as an operating systems engineer, I'm pretty familiar with building reliable and high performance software, but was a bit out of my element building a web application. It was certainly my goal to build a robust and reliable system, but it was hard to know all of the best practices, let alone implement them in a weekend hack. Some places this shows through. Nonetheless, I'm proud of the result and what I was able to build in a day and a couple of evenings of coding, and wanted to share some of the problems and solutions I encountered. I'm happy to get feedback on this article, both about the project and the presentation here.

System Architecture

There are several major components to the Place Matrix system. First, there is a web application hosted on Amazon AWS. It is a Flask app written in Python, and hosted via Amazon's Elastic Beanstalk. EB set up a frontend load balancer and some other stuff automatically. There's an Amazon RDS hosted MySQL database that handles all of the persistent data, such as logins and the current state of the display. On the frontend, it's really just a bit of HTML and Javascript. I used Google Sign-In to support authentication functionality. Second, the hardware is implemented with a Photon Particle controlling The Matrix project from Boldport Club, which utilizes the AS1130 LED driver chip. Finally an iPad Pro streams video to an iMac, which relays the video to YouTube for streaming.


The primary motivation for this project was to do something neat with The Matrix, a project I received as part of my membership to Boldport Club. The community, especially the Slack channel, is inspiring in what they do with each month's project. After soldering 120 LEDs and that tiny SSOP-28 packaged AS1130 chip, I just had to find something worthwhile to do with it. Reddit's Place project seemed like the perfect inspiration. I used a hot-air pencil and solder paste with a stencil to solder all of the LEDs, and drag-soldered the chip on the back. At first all of the LEDs seemed to light up, but many were dim. I had figured I had overheated the LEDs when soldering, but the real problem was poor soldering of the chip. I suspect some unconnected, or perhaps a short (but maybe not dead short?) on the AS1130 pins could have caused this. Re-soldering the chip, followed by thorough cleaning with a Q-tip and isopropyl alcohol fixed it.

It was easy to wire this board to a Particle Photon that I had on hand. I crimped some pins for a Molex KK connector and used a solderless breadboard as a base on which I wired up power and SDA/SCL pins from The Matrix to the Photon. I had to shave the latching tabs off of the connector with an X-Acto knife to fit the connector housing.

Embedded Software

The first step to writing embedded software was getting a development environment working. I like the Particle platform because it allows easy OTA firmware updates, but in this instance I got off on the wrong foot. I wedged two separate units such that they wouldn't be recognized by the Particle web IDE and exhibited the dreaded "dim blue LED" symptom. One of them would get physically hot, and the other just wouldn't seem to respond to commands to download code. The hot one appears to have been previously physically damaged, but the other just needed a fresh firmware download in DFU or Safe mode.

I didn't keep a perfect record of what commands were necessary to recover the Photon with the dim blue LED, but I believe it was as follows. Might have also used Safe Mode instead of DFU before running the "particle update" command.

  • Download Photon Command Line Tools & native IDE
  • Use Homebrew to install dfu-util
  • brew install dfu-util
  • Connect Photon to Mac via USB
  • put Photon into DFU mode.
  • particle update
  • build sketch from the IDE against the latest FW version
  • put particle into DFU mode again
  • particle flash --usb <compiled_file_name.bin>

Writing the embedded application was pretty easy and ended up being less than 100 lines of code. I used the LRAS1130 library to talk to the hardware. The application consists of two functions, one takes a 4 character string that encodes a coordinate and toggles an LED. The second takes a Base64 encoded string, which represents a bit-array to write to the whole display. Both of these functions are bound to the Particle Cloud, so I can call them via a rest API, making integration with the backend very simple. I needed Base64 encoding to efficiently pack the 120 bits of data into the argument string length limit of 63 characters. I had first implemented the dead simple toggle function, but realized I needed to be able to write the whole display for consistency and resilience to power outages and the like in the real application. Before the project was done, I also added an LED test function to the API so I could verify my soldering.

Once on camera, I also found the Particle status LED distracting, so I suppressed it in the nominal state using the following code:

void loop() {
    if (Particle.connected()) {
        if (!RGB.controlled()) {
            RGB.color(0, 0, 0);
    } else {
        if (RGB.controlled()) {

The night before I launched the project, I figured I should try to cleanup some solder joints. I spent quite a while resoldering that SSOP-28 package until I got consistently bright output. It was useful to look at the wiring diagram in the AS1130 datasheet, which The Matrix adheres to, in order to figure out which pin on the chip was improperly soldered.

Unfortunately no matter what I did I found the bottom two LEDs in the second column would not light. I resorted to probing signals at the LEDs with my oscilloscope, and though it was hard to interpret what was going on, I got the sense they were electrically connected but just weren't being commanded to turn on. At my wit's end, I tried using the LEDTest example included with the LRAS1130 library and was surprised to find all of the LEDs lit. After quite a bit of head scratching, I noticed user @tardate had committed a bug-fix to the library addressing a corruption issue. After pulling down that latest version, everything worked great. I'm so greatful to Lucky Resistor and contributors to the library, as it allowed me to focus on the app, rather than implement the protocol talk to chip. Couple of hours spent there, but I was happy to finally have success!

Source available below.


By far, the majority of the work went into the Flask web application. I picked Flask because I was already comfortable with Python and had previously built some simple server apps using Python. As an added bonus, the templating engine was familiar from my experience with Liquid, which I've used with Jekyll on this website.

I started by following an arbitrarytutorial to get the app up and running and talking to a database. It was pretty easy to rapidly iterate by running the development server locally, and talking directly to the MySQL database hosted on AWS, which let me avoid setting up a local database server, or having a different configuration for production. It also allowed me to just manually do database migrations as the datamodel changed.

I added a couple of REST endpoints that were easy to call from javascript on the page via XMLHttpRequests. I stripped out the existing functionality of the tutorial and my friend Charlie Deets helped me design the button grid and layout the content on the page. It took some work, but I managed to create a simple database model that would log each toggle request.

While I was reticent to require login, it was the easiest path to prevent abuse of the system. I let Google handle the authentication, then eventually when I needed to block misbehaving users, it was easy to uniquely identify users and revoke access as necessary. I couldn't have built a competitive system without seriously rat-holing down some abuse prevention path.

At one point, i broke the app and hadn't been doing a good job of separating my work into separate commits. I thought I had messed up the configuration, or something on the server was broken—later I found it was a programming error. The problem was I tried to delete my EB instance, but found it wouldn't get recreated, because the security group which the tutorial suggested I setup, depended on the instance. It wouldn't restart until I removed the instance from the security group. It seems like there was another way to setup a DB instance for the EB application—rather than set it up independently like the tutorial recommended, but I didn't have the experience to try it another way. Add a code snippet of HTTPS redirect. Security Groups. RDS hopefully handles the load? SQLAlchemy frustrates me. monitoring visitors with Google Analytics and AWS dashboards. Forcing SSL. Secret operator page (screenshot, encoding of google User IDs) which provides transcript of transactions. Did database migration by adding

video streaming

Air Server. iPad App. Youtube Embeddign options in iFrame API.

Accessories (the clock)

Performance, operations, and stats so far. Include part about creating a block list. feature, etc. I did a database migration by just modifying the SQL live. I hear this is not best practice:( Over 500 users on April 14th.

I plan on eventually publishing the source to the web application and backend, however cannot publish the software running on the Particle, due to the fact that it uses a GPLv3 licensed library, and am unwilling to release software that I wrote under that license. It's pretty simple though, so should be easy to recreate.

Source Download

Place Matrix

Reddit put together what was ostensibly an April Fools' joke that allowed users to "place" one pixel at a time on a large canvas. It turned out to be a really awesome social art project; groups needed to collaborate to get anything done because there was a long delay between opportunities to place pixels.

Update: Incidentally, Reddit published a great article today about how they built r/Place. Highly recommended.

Because I'm not a big Redditor, my friend Andrew showed this to me, I think after a post on Twitter. We had a great discussion about the emergent behaviors that occurred with such a simple system on Saturday night, and talked about how such constraints can make things a lot of fun. I had just finished building my p11-matrix project from Boldport Club, and had connected it to the web with an API that only allowed toggling a single pixel.

So the next day I woke up and realized I had to port Place over to meatspace and started hacking. Thanks Andrew for helping incubate the idea. I'm not a web programmer, but my Python skills aren't too bad so I found a tutorial on Medium and started setting up AWS Elastic Beanstalk. One full Sunday of programming (followed by 3 back-to-back late night debugging sessions…) and it works. Lots of thanks to my friend Charlie for help and support through these manic last couple of days, and to the Saar for making Boldport Club and inspring projects.

Check it out at Place Matrix.


Weston 1293 Nixie Tube DVM

A couple of years ago I was at an estate sale with my mom and picked up this interesting Weston 1293 Digital Volt Meter. Could not resist nixie tube test equipment for $15.

Weston 1293 DVM

I'd learned a lot about how it worked from a web page describing the Weston 1294, though that web page appears to be completely gone from the internet without a trace—not even a page is cached in the Internet Archive. I hope that site has a shorter hiatus than mine did…

Internals (analog and digital boards)

It had been sitting on my shelf without much use in the interim because it was hard to use with just bare wires soldered on a connector on the back, so finally I've gotten around to building an enclosure for it. I also found an original manual for the Weston 1294 on eBay, which provided more context, though there are numerous differences.

Enclosure Construction

Construction was relatively straightforward, with internal wiring mostly implemented with crimped spade termination and plenty of heatshrink. The most interesting part of the construction was cutting out holes in the aluminum front and rear panels of the enclosure. First I marked the cutouts using blue masking tape. Then I roughed out the holes with a drill and a jigsaw, finally finishing it up using a file. I think this practice of roughing out a hole and filing it to the line must be a standard technique, but I didn't really know how to do this until I saw the amazing craftsmanship on the ClickSpring YouTube channel, where this technique is used a lot.


Omnichrome 643

Recently I purchased a Melles Griot Omnichrome 643 laser on eBay (as noted in my laser inventory). I was happy to find it arrived in great condition after making the long trip from Canada. I had long wanted an Argon-Krypton laser capable of producing a wider slice of the spectrum—"whitelight"—but they seem to be quite a bit more rare than plain old Argon-ion lasers, and usually more expensive. Got lucky with this one.

It came with almost everything including the laser itself, power supply, cooling fan unit, and even a printed manual. It was almost ready to run out of the box, but I needed a cable that connects the laser head to the cooling unit, an air duct, and also a way to plug it in; it draws 20A @ 240V.

First I wired up a 10 gauge extension from my electric clothes dryer outlet with a NEMA 10-30 plug to a NEMA 6-20R receptical. I ordered 25ft of 10/3 SOOW cable and the plug from Amazon and picked up a "handy box" and the receptical at Lowes. Working with these heavy, flexible SOOW cables reminds me of my days in highschool technical theater…

I couldn't find one on eBay, so parts for the other cable required a new crimper (Engineer PAD-01), a Digi-Key order, and tracking down some 18/6 SOOW at a good price. Fortunately it was easy to defeat the fan interlock with a jumper and use another blower I had for my other Argon laser in the mean time.

So after just a bit of wiring and basic external cleaning I was able to get it running in top shape. I made a new jumper remote plug to run it in constant-current mode and walked the mirrors to get the peak output up to about 83mW at max current. I figure the cross-continent shipping probably wasn't great for mirror alignment, but no worries now. The specific model number is 643-OLYM-AO3, which I suspect means it came from an Olympus confocal scanning microscope, but have no explicit specifications for the unit. I received the tube with about 570 hours on the run time meter, so it is far from new but still has great light output. Anyway, on to the pictures!

One day I think I might be interested in getting RGB optics instead of the RYB this unit comes with so that it'd be more appropriate for laser display purposes. Some folks suggest that it is best to appreciate the yellow-green line for what it is and avoid the trouble. Guess we'll see if I come across the right kind of output-coupler optic. Next project is to build a small digitally-controlled remote for the 171-B power supply.

I'm back!

After a hiatus of more than 5 years, I’ve resurrected my website! I’m hoping to share some project stories, add back some archival content from the old site, and have a place to share things I learn.

Years ago I took down my website because my VPS had been exploited, I think due to an outdated version of Wordpress. This new one should be more reliable; I’m using Jekyll hosted on Amazon AWS using S3 and CloudFront, which made it easy to adopt SSL and HTTP/2. I wrote a custom Jekyll plugin to handle automatic thumbnail generation for images and Lightbox stuff. Fun new project!

I’m slowly bringing back some old content on the blog, such as my post about building a Blu-Ray Laser Pointer, and have refreshed some of the content in the Lasers and Panoramas sections.

subscribe via RSS