I made a thing
I think it's pretty cute

May 2019

The Thing I Made

My girlfriend and I have an inside joke: once upon a time, she made a remark about becoming a trophy wife, and I thought it would be funny to give her an actual trophy. This made her the (proud) owner of the (coveted) Best Girlfriend 2017 award. Then 2018 came, and I thought - Oh man - what do I get her this year? Maybe I could up the ante by making a trophy for her instead of buying one.

A while back, I had seen this tweet:

Source: Twitter

I thought this was such a cute idea, but I wanted to make some changes. I decided to make two trophies - one for me, one for her - and when one trophy’s button is pressed, the other trophy would light up. This would also be more fun for me, because I didn’t have any experience working with hardware.

But before we get too far in, here’s a short clip of the final product:

Architecture

Software

Since we were going to be long-distance that year, the trophies couldn’t be entirely peer-to-peer (e.g. Bluetooth-only), and connections had to be orchestrated by a server. To manage this, I built a tiny server with two endpoints: one to send a ping, and another to check for pings. That’s actually all there is to this server: there’s not even a database of pings; the server keeps track of that in memory. I figured that this was fine for a server that would only ever be accessed by two trophies; if I decided one day to make a bunch to sell, I could always upgrade the code.

Hardware

*Note: if you know anything in the wheelhouse of electrical engineering, this will probably be really boring, but as a software guy, I had a lot of fun learning about the hardware side of things.

Talking to the Server

First things first: the trophy needs to be able to connect to my server, so it needs an internet connection. I used an ESP8266, which is a networking chip with Wi-Fi and Bluetooth receivers. It’s often used to provide an otherwise unconnected Arduino some network access, but because it has 1MB of flash memory, it can also be programmed as a standalone chip. There are some libraries that make it pretty simple to open a HTTPS connection. Here’s how easy it is:

const char* HOST = "my-server-location.com";

//SHA1 SSL fingerprint to verify SSL connection
const char* fingerprint = "** ** **"; 

WiFiClientSecure client;
if (!client.connect(HOST, 443)) return;
if (!client.verify(fingerprint, HOST)) return; //See note below
client.print(String("GET ") + "/checkForPings?trophyId=1" + " HTTP/1.1\r\n" +
  "Host: " + "my-server-location.com" + "\r\n" +
  "Connection: close\r\n\r\n"); //GETS this url

client.readStringUntil("\n"); //to read each response line

/*
Note: When SSL certificates are rotated, the fingerprint 
associated with the website will change and this code (using 
a hard-coded fingerprint) will stop working. Currently the 
ESP8266 doesn't seem to have a library to verify certificates 
automatically, so I've elected to proceed with code execution 
no matter what client.verify() returns given there is no
sensitive information transmitted.
*/

Turning on the lights

The next step is to make the ESP8266 actually turn on lights. My first approach was connect LEDs to the output pin of the ESP8266 like so:

const int LEDPIN = 3; 

OFF:

digitalWrite(LEDPIN, LOW);

ON:

digitalWrite(LEDPIN, HIGH);

This works! And it makes sense why: when the output is HIGH, the ESP8266 is providing 3.3V to the LEDs, which light up.

There’s a problem, however: the LEDs require 80mA, but the ESP8266 is recommended to only supply 6mA.

We can get around this problem by using a transistor:

The key part here is the transistor, which will reduce the current drawn from the ESP8266.

Note: If you’ve built a circuit before, you’ll notice that these diagrams are sorely missing resistors. I have included them in the final schematic, but left them out for illustration here.

How do we use a transistor?

Source: Sparkfun

A transistor has three pins: a collector (connected to a source of power), a base (our ESP8266 chip), and an emitter (the LEDs). In this case, because this is an NPN transistor, when the base is LOW, no current flows to the emitter. When the base is HIGH, current flows from the collector and base to the emitter, which powers the LEDs.

We know the following:

  • IE = IB + IC (current at the emitter comes from the base and collector)
  • IE = 80mA (required to drive our LEDs)

And we need to ensure that:

  • IB <= 6mA (recommended maximum current from the ESP8266)

We can look at a ratio called the DC Current Gain or hFE, which is the collector current divided by the base current (IC/IB). This value is not constant: it can change depending on the current at the base and the voltage, so manufacturers provide data sheets with sample test cases.

This is an example data sheet:

Source: Central Semiconductor

Although there’s no IC = 76mA test case, it looks like assuming hFE >= 400 is reasonably safe.

Thus:

  • hFE = IC/IB = 400
  • IC = 400 * IB

Recall that:

  • IE = IB + IC

So by substitution:

  • 80mA = IB + 400 * IB = 401 * IB
  • 80mA401 = IB
  • 0.2mA ≅ IB

0.2mA is well below the recommended 6mA rating, which means the inclusion of this transistor prevents us from accidentally ruining our chip.

Button Presses

Registering the button presses to turn on the other trophy was fairly straightforward.

I defined an input pin on the ESP8266, and told it to listen to changes in the voltage. This occurred every time I pushed the button, because a depressed button would connect the pin to ground, and cause it to register LOW.

When this happens, we raise a flag in the code.

Then, every few seconds, the ESP8266 checks the flag and if it’s been raised, it talks to the server to let it know the button has been pressed.

//Global Flag
volatile bool sendPulse = false;

//Set Pin 1 as the input pin for the button press
pinMode(1, INPUT_PULLUP); 

//Attach event listener
attachInterrupt(digitalPinToInterrupt(1), pulsed, CHANGE);

//Event Handler
void pulsed() {
  sendPulse = true;
}

//Main Event Loop
void loop(){
  if (sendPulse) {
    //Set up HTTPS connection and send the ping
    sendPulse = false;
  }
  //Do other stuff in the event loop
  //Sleep for a few hundred milliseconds
}

Trophy Design

At this point, I had all the core features working on a breadboard, and my chip could do the following:

  • Receive button presses and send a ping to the server for the other trophy to receive
  • Check the server every 5 seconds for a ping from the other trophy
  • Turn the lights on and off for 10 seconds at a time

The next step would be to migrate my circuit from a breadboard to a dedicated circuit board. But first, I had to figure out the physical trophy design - this would inform the dimensions of the circuit board.

I went through a bunch of potential designs, but I settled on an acrylic heart sat upon a David’s Tea container. This was a fairly shoddy mockup, I’ll admit, but I thought it was fairly promising.

Testing out different heart sizes - this one is around 14 cm across, which is what I ended up going with in the final product.

In this design, the acrylic heart would extend inside the tea container, where the circuit board would be hidden. This meant I had to get my design onto a board that was at most 5cm wide, or else it wouldn’t fit.

Circuit Boards

Some hobbyist friends helped me get set up with EagleCAD, in which we made this schematic:

We turned this into a board fairly easily: once the schematic is in place, EagleCAD lets you drag and drop components onto the board design and draw the connecting circuit paths as required. One tip that I got was to use the ratsnest feature. This basically draws an area that is one giant circuit path, which is really useful because it means once you draw the lines connecting your power, ratsnest can immediately ground all the remaining pins on the board.

I also drew an outline of my last name in Chinese (林) just for decoration - if you look closely, you can see it on the actual board.

Final board layout - red lines are circuit paths on the top face, while blue lines are on the bottom face.
Printed circuit board. If you look really closely, you can just barely see the contours of the 林.

Notice the holes in the upper left and right corners: those were drawn in so I could mount the board and its lights directly below the acrylic heart, so the light would shine directly into the material.

Miscellaneous

  1. Acrylic Laser-Cut Heart: I learned to use SolidWorks just enough to make a drawing of the acrylic hearts. My school’s laser cutter was set up to accept a SolidWorks drawing and engrave/cut based on line thicknesses and colors. This was a fairly straightforward (though glacial) process; I just didn’t really understand the SolidWorks UI.
  2. 3D-Printed Base: For reasons that I’ll never know, the school’s laser cutter caught on fire at an inopportune time: after I’d cut the hearts, but before I’d cut the circular base to mount the hearts to. This was actually a blessing in disguise - I 3D-printed the base instead, which made it easier to undersize the slot for the heart and file it down to ensure a tight fit.

Final Product and Fabrication Process

I forgot to carefully document every step of the fabrication process, so this is a loose collection of images at various stages of the process from start to finish.

Final product first - the completed trophy sitting on my girlfriend’s desk.
Hearts fresh out of the laser cutter and smelling like smoke! I had to pick these up during a break, so I was rushing back to class while taking this photo.
Testing that 4 LEDs are enough to make the text show up. I realized that the outside edge of the heart was difficult to see, so I ended up beveling them with a file to help them catch the light.
Soldering the circuit board. It’d been years since I’d last done any soldering, so I made a few mistakes that required a utility knife to fix.
Drilling holes in my tins to make the cutouts I need to fit the circuit board, button, and power supply.
Fit check with the 3D-printed base and laser-cut heart. I printed the opening in the base a little smaller than required and filed it down to ensure a tight fit.
All the parts ready for assembly!
I glued a trophy wallpaper to the outside of the trophy to mask the David’s Tea logo and text. In hindsight, a simpler wallpaper (or spray paint) might have been better.
Joining the heart to the base from the bottom. Some helpful guys in the machine shop told me that baking soda and superglue would form a really strong bond, so I’ve masked off an area for the baking soda here.
The circuit board is now attached to the heart through the tea tin lid. You can also see the thick crust formed by the baking soda + superglue combination. Just have wrap the entire tin with the same wallpaper and we’re ready to go!
And finally, once again, the finished trophy. You can see the Best Girlfriend 2017 trophy on the right as well!