Building a Wireless TOTEM Split Keyboard

Oct 23, 2026    #tech  

The reason I got into split keyboards is simple: my back muscles were always tense. On a regular keyboard my hands sit close together, and my shoulders end up pulled forward and in all day. And when my back is tight all day, I tend to feel more on edge too. With the two halves apart, my hands can rest at shoulder width, which feels a lot more relaxed.

The split keyboards I found on the market were all too big to carry around, though. Then I came across TOTEM, an open-source split keyboard small enough for a backpack pocket, and decided to build one myself. Here is how it went.

Choosing the parts

TOTEM is a 38-key, column-staggered split keyboard by GEIGEIGEIST. I built the wireless version: each half has its own Seeed XIAO nRF52840 and a small LiPo battery, and the two halves talk over Bluetooth, so there’s no cable between them.

PartChoicePer keyboard
PCBTOTEM v0.3, made by JLCPCB1 pair
ControllerSeeed XIAO nRF52840, no headers2
SwitchesKailh Choc V1 Red Pro, 35 gf38
Hot-swap socketsKailh CPG135001S3038
Diodes1N4148W, SOD-12338
Power switchMSK-12C022
Reset buttonALPS SKHLLCA0102
Battery601520 LiPo, 3.7 V, 200 mAh, with protection board2
HardwareM2×6 standoffs, M2×6 countersunk screws, 8 mm rubber feet8 / 16 / 8

JLCPCB’s minimum order is five boards, so I now have four spare sets lying around.

TOTEM PCBs from JLCPCB

Printing the case

The case, the switch plates and even the keycaps are all 3D printed, on a Bambu Lab X2D. I used the hot-swap version of the bottom case and angled MOTE keycaps for Choc V1.

Funnily enough, most of the trouble came from the slicer, not the printer: the wrong number of copies, parts overlapping on the plate, a setting I forgot to change. Everything is printed in PLA, and it has held up fine. If you want something stiffer that also makes assembly easier, I’d go with a carbon-fiber filament like PETG-CF.

PCB, printed plate and case, XIAO, diodes and switches

Soldering and testing

I flashed each XIAO first, just to make sure the controllers worked, and then soldered the diodes, sockets, power switch, reset button, controller and battery. The 38 diodes are tiny SOD-123 parts, so tweezers and flux were a big help.

Testing before closing the case saved me twice 😅 One half wouldn’t run on battery, because its BT+ and BT− pads weren’t really connected. And one key didn’t respond: shorting its socket pads with tweezers confirmed the problem, and the diode’s reference number on the PCB pointed me straight to the bad joint.

Firmware

The keyboard runs ZMK. I set up a QWERTY layout for the Mac with home-row mods, so Cmd, Option, Ctrl and Shift live under the home row, plus thumb-key layers for navigation, symbols and Bluetooth. GitHub Actions builds the firmware on every push, and flashing is just dragging a .uf2 file onto the XIAO. I also wrote an English keymap guide (PDF) to keep next to me while learning the layout.

Getting an accurate battery reading

The battery level got stuck at around 79% and 91%, and never reached 100% no matter how long I charged it. The battery itself was fine. ZMK’s default estimate is a straight line between 3.45 V and 4.2 V, which works as a general default, but a fully charged LiPo settles a little below 4.2 V. On top of that, each XIAO reads the voltage a few percent low, by a different amount on each board.

So I wrote a small battery driver that maps the voltage onto a LiPo discharge curve, with a correction factor per board (+3.7% on the left, +1.2% on the right). Now both halves show 100% after a full charge.

Seeing both halves

macOS only shows the left half’s battery, so I had ZMK forward the right half’s level too, and built two ways to see both.

The first is a status page that reads them over Web Bluetooth. Chrome on macOS only lists devices that are advertising, and ZMK stops advertising once it’s connected, so I added a key that makes the keyboard advertise for 10 seconds without touching the existing connection.

Battery status page

The second is a small native menu bar app for macOS. A colored dot shows whichever half is lower, and the menu lists both levels. It just listens for the keyboard’s battery notifications instead of polling, uses about 13 MB of memory, and lets me know when a half runs low or the right half loses its link.

Menu bar app

Battery life

After a few days, the left half was draining about three times faster than the right. That’s how Bluetooth works here: the left half is the central of the link between the halves, so it has to wake up every 7.5 ms, while the right half can skip most of those events when it has nothing to send.

A longer interval would add delay to every key on the right half, and I type fast enough to care. So I made two changes that leave typing alone:

It’s still too early for numbers, so I’ll see over the next few weeks how much the gap closes.

Tips if you want to build one

And most importantly, my back does feel better.

One more thing: my background is in computer science, and while I knew the basics of hardware, I hadn’t gone very deep into it. I got through all of this with a lot of help from AI, so special thanks to Claude and Codex, which helped with everything from picking parts to writing the firmware. In the age of AI, building whatever you have in mind is no longer the hard part.

Big thanks also to GEIGEIGEIST for open-sourcing TOTEM, and to the ZMK project for the firmware this all builds on.