A little over three years ago I made a custom keyboard to help speed up the process of laying out a PCB in Eagle. Truth be told, I only ended up using the keyboard for a short amount of time. It wasn't that the keyboard wasn't useful; the main issue was the case wasn't complete. It sat flat on the desk, and I was using pieces of thermal gap filler as feet to keep it from sliding.
Combined with the fact that it used a frequently needed micro USB cable, and the next closest cable was
miles ten feet away from my desk, it became a tool that spent most of its time in my desk drawer. What I was missing was a little bit of inspiration to invest the time to do it right.
A few months ago I saw a library for the ESP32 that used the Bluetooth radio and turned the ESP32 into a Human Interface Device, or HID. The original keyboard didn't have enough space to easily fit the ESP32 Thing Plus I wanted to use, so it forced me to fully enclose it like I originally intended:
The new box I made had more of an ergonomic pitch that matched my keyboard, starting at around an inch high in the back and thinning down to around half an inch in the front (making sure to leave room for the Cherry MX key body). I used CA glue to hold five of the six sides in place, and black electrical tape to keep the top in place. I was pretty happy with the shape and feel, and I reclaimed some of the functions the previous keyboard had, plus a few new ones:
- Left Knob: Volume Up/Down and Mute
- Right Knob: Eagle Grid Spacing +/- and switch between Imperial/Metic
- LED Indicator: BLE connection status and battery indicator
- 16 Cherry MX keys for:
- Skip Forward
- Skip Backward
- Launch Calculator (really useful for footprint creation from a datasheet)
- 12 frequently used Eagle shortcut keys
Making the keyboard wireless gave me the flexibility to move it wherever I needed. It also, however, gave me more challenges to think about - mainly power management.
To start, I checked to see how large a battery I could physically fit, and settled on a 2000mAh battery. While the library uses Bluetooth Low Energy, it was not exactly what you would call low energy. After pairing to my computer, the ESP32 was drawing around 83mA, which means it would barely run for a full 24 hours.
Quite a few years ago when I had a wireless mouse, the number one thing that drove me crazy was that I had to charge it every few days. Often I just left the USB cable connected to keep the battery charged and went wireless only when I had to. Having that still in my mind, I wanted to make sure I didn’t run into the same issue again. By putting the ESP32 to deep sleep you can power down parts of the chip you don’t need to use, like the radio, analog to digital converter, etc., to significantly cut down on power and extend the battery life.
Every time the board wakes up, the time it takes to reconnect to the computer can vary, so I needed a way to tell when it was trying to connect, and whether it was awake or asleep. I also needed to know when it was time to charge the battery. The library has a function to send the battery percentage to the computer (shown in the image above), but it wasn’t updating on the computer reliably enough to count on. I solved all of these issues with a single red/green led between the two encoders:
Alternating red and green when pairing (which looks better in person than on camera):
Double green blink when it’s connected and active:
Double red blink when it’s awake and needs charging:
The LEDs draw less than a couple milliamps of current, but if you only flash the LEDs periodically, especially for when the battery needs to be charged, you can get the most out of the battery. To decide when to go to sleep, I monitor any key presses and reset a timer, so that if after 20 minutes the keyboard hasn’t been used, it will put itself to sleep. The biggest downside admittedly is that because I used a voltage divider on the keys, I can’t use them to wake up from sleep. I did try to leave the ADC powered on, but I measured 20mA of current was still being used because it was constantly polling the ADC to see if a key was pressed to wake up.
The other power management solution I came up with was adding a switch to pull the enable pin of the 3.3V regulator down to ground, which cuts power to the ESP32, but will still allow the battery to charge if power is connected.
Speaking of charging the battery, I used a USB-C Breakout along with some wire wrap to provide not only power for charging, but the USB data pins as well so that I can reprogram the board without having to open up the case and stress the wires connecting the keys to the ESP32.
Aside from that, it behaves exactly like the wired version. I’m not exactly sure what the normal use battery life is quite yet. I’ve had the board running for about a week now without charging, aside from making a few quick tweaks to the code.
If you’re interested in making your own, you can check out the wishlist for the parts used, and the GitHub repo, which has the files for the box, code used, and schematic for the hardware and images for the keycaps I used.
Two parts not on the wishlist are the common anode red/green LED and the switch, which were parts I had laying around in my parts bin, but you should be able to easily edit the size of the holes to match your parts.
comments | comment feed