← Writing

The Scale Broadcasts. The Agent Decides.

  • #iot
  • #raspberry-pi
  • #bluetooth
  • #ai
  • #agentic-engineering
  • #self-hosting
  • #personal-software
  • #side-projects
  • #python

My bathroom scale is a generic Xiaomi. Nothing special: the cheap one everybody has. It is also, now, connected to every system I run — my server, my own tracker, my AI assistants — and it talks to them on its own, without me touching anything.

So the morning goes like this. I step on, I step off, and a few seconds later my phone has this:

Aura chat on a phone: an automatic scale event for 79.90 kg, and the assistant's reply noting the trend with a small chart
The reply, on my phone.
Soma Tracker on a phone: today's weight of 79.55 kg, the smoothed trend at 79.38, and a 90-day chart with the goal band
And the row, in the tracker I built.

I didn’t open any app. The manufacturer’s app isn’t even installed anymore.

The number used to be theirs

For as long as I’ve had the scale, the routine was: step on, then stand there with the phone in my hand, open the vendor’s app (Mi Fit, later renamed Zepp Life), wait for it to find the scale over Bluetooth, and hope the sync went through. It often didn’t. When it did, the number lived in their cloud, in their app, in their format — while the number I actually wanted, in my own tracker, still had to be typed in by hand.

What bothered me wasn’t the thirty seconds. It was that the data was being produced a metre from my own network and I had no say in where it went.

Now the reading never touches anyone else’s software. Within seconds of stepping off it exists three times over on machines I own: as a line in a file, as a row in my tracker, and as a message in front of an assistant that knows what to do with it. From there I can point it at the tracker, at the assistant, at something I haven’t built yet — all the same one-line change. That isn’t a better way to type a number. It’s a different category of thing.

How it works, in five steps

Five steps in a row: the scale broadcasts the weight, a small computer at home hears it over Bluetooth, my server writes it down and passes it on, my assistant decides what to do with it, and my phone shows the reply
The whole thing, five steps.
  1. The scale broadcasts every reading over Bluetooth, to nobody in particular. It always did; nothing was listening.
  2. A small computer in my study hears it and turns the burst of signals into one clean message.
  3. It sends that message over my private network to my server, which writes it down before doing anything else.
  4. The server hands it to my assistant, which decides whether it counts and stores it in my tracker.
  5. My phone gets the reply: logged, and here’s the trend.
Xiaomi Mi Scale 2 on a bathroom floor, display reading 79.90
The scale. The generic one.
A white-cased Raspberry Pi 3 B+ on a desk next to a keyboard
The small computer, in its case, in the study.
The Pi case opened, showing the board inside
Inside the case: the whole listener is this board.

The interesting part is step 4, because “decides whether it counts” isn’t code. The message that arrives is this, and the rules travel with it:

That paragraph is the whole rulebook. Changing it means editing a sentence, not reflashing a device.

Why it was small: the pieces already existed

This is the part I actually care about, because the scale is the least interesting piece. The project was small because almost everything it needed was already running in my house:

Four cards: Aura, where my assistants live; my own apps, my data on my machine; a small processor, new in this project, turning a physical event into a message; a private network holding my devices
Four pieces. This project added the third one.

Aura is the app I built to talk to Claude Code sessions from my phone, with characterised assistants on top — one of them handles wellness. Anything that can post a message into a chat can put work in front of one, so that’s the whole integration: a message. Soma Tracker is a small API and a database file on the same machine, so an assistant needs no plugin to use it. The network holds my devices as if they were in one room, so nothing has to be exposed to the internet. This project added one new piece and one adapter. Everything else was already there, doing something else.

What it takes to build one today

The thing I want to leave here isn’t the scale. It’s that wiring a physical device into your own systems, at home, is no longer a project. It’s an afternoon.

To be fair to the past, this was easy because the hard pieces already existed. The tracker took evenings, Aura took months: the first piece is the one that costs you, the fifth is a script. The only thing I gave up is immediacy — a reading takes about a minute to land instead of appearing at once.

A whole IoT system, for a number on a bathroom floor

I didn’t set out to build an IoT system. I set out to stop opening an app. But that’s what came out: a sensor, a small computer at the edge, a private network, a server, an agent that decides, and a loop back to my phone. Every textbook piece, for a problem no bigger than a number on a bathroom floor.

That’s the part I’d keep. When the pieces are yours, the size of the problem stops mattering: the same shape that logs a weigh-in would log anything else that happens in this house, and a small problem is the cheap place to learn the shape.

The scale hasn’t changed. It’s still the cheap one everybody has. Everything around it did.

Appendix for builders: the full map

The five-step picture is the honest summary. This one is the real map: every hop, what runs where, and which box is allowed to have an opinion. If you want to build something like this, it’s the diagram I’d want to be handed.

Detailed architecture diagram: the scale broadcasts over Bluetooth to a Raspberry Pi at home; the Pi sends one event over the private network to a relay on the server; the relay writes it to a file and wakes the assistant, which stores it in Soma Tracker through its API and replies in the chat on the phone
The faithful version: home on the left, my server on the right, the reading's path in blue and what comes back in grey. Click to open full size.

Two design decisions carry the whole thing.

The Pi has no credentials and no rules. About 140 lines of Python. It listens, ignores anything that isn’t a final reading, collapses the burst of broadcasts from one weigh-in into a single message, and sends it. It doesn’t know whose weight this is, whether it should be stored, or what “one per day” means. It knows someone finished weighing and says so.

The relay writes first, then asks. Seventy-odd lines on my server, no libraries. Every reading is appended to a plain text file before anything else happens — always, even if everything downstream is broken. That file is the copy I own: searchable, exportable, nobody’s cloud. Then it wakes the assistant. If that fails, the reading is still on disk. The relay never writes to the tracker; it doesn’t know the tracker exists.

Everything else is the boring glue in the diagram.