My Balance Box

It's about time we started to accept that humans have emotions, and share them with each other. As part of my ongoing commitment to radical vulnerability, I built a box that tells everyone how I feel in real time.

There's a box sitting on my desk. Three sliders, and a number above each. How I feel in myself, how I feel professionally, and how I feel spiritually. With 0 being the worst, and 9 being the best. I try to keep it updated:

Of course, updating my website instantly isn't doable. It's one second out of date:

You really are seeing it in real-time


Online, we curate an image of ourselves, like a personal brand, by only presenting one side of day-to-day life. For many of us, it's the same at work too. Opening up is uncomfortable, because it makes us feel vulnerable. Even though we know that everyone else has bad days too, it doesn't feel nice to admit it.

I recently finished reading Agile Conversations, which talks in detail about Argyris' two models of reasoning. That last paragraph is a clear example of Defensive Reasoning (aka Model I), which we tend to use when there's something important on the line. Defensive Reasoning is undepinned by four principles:

  1. Achieve the purposes as the actor perceives them
  2. Maximise winning and minimise losing
  3. Minimise eliciting negative feelings
  4. Be rational and minimise emotionality

You can probably think of a time when you followed those rules, trying to win an argument. Contrast that with Model II, Productive Reasoning, which aims to foster relationships and collaborate towards the best possible solution:

  1. Valid information
  2. Free and informed choice
  3. Internal commitment to the choice and constant monitoring of the implementation

If I asked how you thought people should act in a discussion, you'd probably describe Model II. If I put you in a group, and offered a cash prize for the person who won the argument, you'd probably exhibit Model I.

Defensive Reasoning is stressful, harms relationships, and produces worse outcomes. Screw everything about that. I have always preached openness, authenticity, and Productive Reasoning, but it's time for me to commit to it. Time to practice what I preach.

I have emotions. And you know what? I have bad days too. And when I'm not feeling great? I'll tell you. This is me, committing to openness, Productive Reasoning, and vulnerability. And there's a big glowing box on my desk to remind me.

The finished balance box. It is a tall box made of black plastic, presenting a front face with three sliders, and a 7-segment display above each. The brightly glowing displays show the numbers 6-7-7.
The Finished Box

Balance Scores

Reading A Radical Enterprise, I learnt about Balance Scores. A balance score is a set of three ratings, describing how you're balancing the different aspects of your life, and giving a little bit of context for how you act. There's no explanation, and no questions or sympathy allowed, just three scores out of ten:

  • Personal - Your mental/physical health, happiness, home life, and general wellbeing.
  • Professional - How much you are enjoying your job, work life, and feeling productive.
  • Spiritual - Encompasses a sense of higher purpose, but ultimately up to the individual. For me, it's a sense of belonging, knowing that I've found my place in the world and have true belief in a mission / purpose.

At the start of each meeting, try going around the room and sharing your balance scores. By openly sharing our emotional state, it becomes much easier to use productive reasoning. It sets the stage for a discussion that fosters relationships, rather than one that damages them.

Of course, everyone will have a different idea of what a 5 means, or even what personal wellbeing is. It doesn't really matter though. Over time, you intuitively understand what someone's baseline is, and whether they're having a good or bad day. It's not really about the numbers anyway, it's about creating a space for emotions and vulnerability, so do whatever works best for you. Feel free to just use good / neutral / bad for each category instead, if that's easier.

I went one step futher, and built a box that shares my balance scores in real time. Just three digits, 0-9, visible for anyone that wants to look. You can see my scores on any blog post, or at https://stevenwaterman.uk/Balance.


The system is conceptually simple, and everything you need to make one for yourself is available on GitHub, including a parts list and instructions. An Arduino is connected to my PC via USB, constantly reporting the current values set on the sliders. My PC writes that to Firestore, which updates any of the browsers currently on the page.

A potentiometer has its voltage read by an arduino. The arduino reports the 3 scores to my PC over serial. My PC sends the data to Firestore. A browser fetches the web page from GitHub Pages, and the data from Firestore.
System Architecture

I'll work my way through each component, giving a brief overview. If you have any questions, check out the GitHub repo, or feel free to get in touch!


I designed the casing in CAD based on component measurements and 3d-printed it on a Prusa i3 MK3S+. I printed most of it in black PETG, and the sliders in grey PLA. It's case is printed in 3 parts, and held together with 4 bolts, which just self-tap into the holes.

The 3d Printer Files for the Case

There's not much else to say here, because CAD and 3d printing are definitely out of scope for this post. If you're looking for printer recommendations, I can say that the MK3S+ is expensive compared to more DIY options, but it's rock solid reliable, and I haven't found anything it can't do (yet). If your hobby is 3d printers, it's not for you. Nothing ever breaks. If your hobby is printing, it's perfect.


A sliding potentiometer is connected between the 5v rail and ground, and its signal is connected to one of the analog pins on the Arduino. That's the only necessary part, and everything else is just for the displays, which are much more complicated.

A potentiometer has its voltage read by an arduino. The arduino reports the 3 scores to my PC over serial. My PC sends the data to Firestore. A browser fetches the web page from GitHub Pages, and the data from Firestore.
Circuit Diagram, One per slider

Each 7-segment display consists of 7 LEDs, each with their own pin named A-G. Because I need to run 3 of these displays, and the arduino doesn't have 21 logic pins, I have to use a shift register for each one. That lets me control the 7 output pins using only 3 pins on the arduino, writing pin states serially and outputting them in parallel.

To limit the current sent through the LEDs in the display, each LED needs a resistor connected to it. I found it really helpful to use some TriPad stripboard to hold everything in place.

Honestly, if I did this again, I'd probably not bother with the 7-segment displays. Instead, I'd use a potentiometer with discrete steps, or mark on the casing where each value was. It does look cool though.


The Arduino polls the 3 potentiometers 60 times per second, and converts their voltages into digits 0-9. If there is any change, it updates the 7-segment displays by writing to the shift registers, and writes the new values to the serial bus.

Below is a shortened version of the actual code, which only contains the code for one of the 3 balance scores. It uses the pin layouts from the diagram above.


/* ...LED constants setup... */ void setup() { Serial.begin(9600); /* ...pinMode... */ } int value = 0; void loop() { int newValue = read(); if (newValue != -1 && value != newValue) { value = newValue; display(); Serial.println(value); } delay(16); } int read() { int sensorValue = analogRead(A5); for (int i = 0; i < 10; i++) { if (sensorValue < i * 110 + 85) { return 9 - i; } if (sensorValue < i * 110 + 105) { return -1; } } return -1; } void display() { digitalWrite(4, LOW); if (value < 0 || value > 9) { shiftOut(3, 2, MSBFIRST, led_g); } else { shiftOut(3, 2, MSBFIRST, digits[value]); } digitalWrite(4, HIGH); }

I have no doubt that there are errors in that code. Feel free to let me know, but no need to bully me for it - C isn't my strong suit. In fact that goes for the electronics - actually it goes for everything here. Let's just agree not to bully people for not knowing things.

Serial Listener

Currently, the Arduino is just shouting into the void (serially). We need something on the other end, to listen. I wrote a Node.js TypeScript app that runs on my PC, listening for incoming serial data, and sending it to Firestore.

Serial (Listener)

import { ReadlineParser, SerialPort } from "serialport"; const port = new SerialPort({ path: "/dev/ttyACM0", baudRate: 9600, }); let timer: NodeJS.Timeout | null = null; let value: number = 0; const lineStream = port.pipe(new ReadlineParser()); lineStream.on("data", (data: string) => { value = parseInt(data[0]); pushUpdate(); });

In the Firestore database, one document (current) is available for anyone to read, which contains my current balance scores. It gets overwritten each time I adjust a slider. I also create a document in the historic collection, which is there for when I want to analyse the data later on.

Serial (Firestore)

const currentDoc = db.doc("current/current"); const historicCollection = db.collection("/historic"); async function pushUpdate() { const timestamp = Math.round(new Date().getTime() / 1000); const data = { value, timestamp }; await Promise.all([currentDoc.update(data), historicCollection.add(data)]); console.log(`Updated ${value}`); }

In the real code, there's also a 1-second debounce timer. This means that no database writes happen until I stop moving the slider. It also means that Firestore doesn't get overwhelmed, because it's not designed to handle more than one update per second on a single document.

For security, I have the database configured to deny all writes, and then I use the firebase-admin package to bypass those permissions. This requires a certificate stored locally, which gets read from storage and passed to firebase-admin. In the future I'll probably integrate authentication so I can update my scores from my phone too.

I expect that this will sit completely within Firestore's free tier - with the only potential cost being $0.06 per 100,000 reads, after the first 50,000 per day. By the time $0.0000006 per page view gets expensive, everything else will have broken.


Finally, we get to the little web app I made that displays my current balance score, https://stevenwaterman.uk/Balance. Like most of my personal projects, it's written in Svelte, hosted on GitHub Pages, and deployed with GitHub Actions.

It uses Firestore's realtime update feature to listen for changes. Whenever the document is updated, a callback is triggered, which updates the variables, causing Svelte to update the page. Following the trend, this code has been cut down to only show one of the three values:


<script lang="ts"> const currentDoc = doc(db, "current", "current"); onSnapshot(currentDoc, (doc) => { const data = doc.data(); if (data !== undefined) { value = data.value; } }); let value: number | undefined = undefined; </script> {#if value !== undefined} <span>{value}</span> {/if}

The real code has a load of extra styling, some transitions, and all of the Firestore config code. Then, to display the balance scores on this blog, I just add an iframe, and it all works nicely! (I still refuse to enable JS on this blog)


This project took much, much longer than I expected. Honestly, it's a good thing that I didn't have the balance scores set up at the time, because I was not having a good time. I'm not showing you inside the box, because it's a complete mess and I'm ashamed of it. But it works!

Everyone can see how I feel, and can get a little bit of context for my actions! I'm committing to being vulnerable, to sharing my knowledge, and to Productive Reasoning.

Next time you're in a meeting, try and think about which model you're using. Try and share your emotions, and the knowledge that you are keeping to yourself. Introduce others to Balance Scores, Productive Reasoning, and Radical Vulnerability.

If you want to make your own Balance box, everything you need is available on GitHub.

Good luck, and have fun!