Field NotesNo. 05
July 30, 20266 min read

My Starter Is Live

I reverse-engineered a starter feeder's cloud API so my sourdough could report its own temperature on my own website. This is, I've decided, a normal thing to do.

bread<dev>
My Starter Is Live

Last time I ended on a small realization: my King Arthur Sourdough Sidekick and my wall oven both live on GE's SmartHQ cloud, in the same app, on the same login. I could open my phone and watch my starter's temperature tick along.

The trouble with watching it on my phone is that only I can watch it. I run a bread website. If my starter has a pulse, it should have a pulse here — on a page anyone can open — not locked inside an app I have to unlock to see. So I set out to get my starter's live status onto my own home page. It took longer than I'd like to admit, sent the whole site to a different host, and taught me a few things about how much of "smart" is just a nicely painted door. Here's the honest version.

There's a real API behind the app

SmartHQ isn't only a phone app — GE runs an actual developer platform at developer.smarthq.com, with a documented v2 API. Two pieces matter for what I wanted:

  • Identity & Access Management — an OAuth 2.0 login that lets my code read my devices, once I approve it.
  • The Digital Twin API — the read side: the current state of each appliance, on demand.

So the shape of the job was: register a developer app, get a Client ID and Secret, do the one-time "yes, this website may read my account" approval, and then quietly poll my own starter forever. In theory a weekend. In practice, the interesting part was everything the theory left out.

The catch that moved my whole website

Here's the thing nobody tells you until you're in it: a live feed — the kind that updates the instant the starter changes, not a page you refresh — needs a connection that stays open. A WebSocket, held open on a server, all the time.

My site was static, hosted on Vercel, which runs code in little bursts that spin up for a request and vanish a second later. Wonderful for serving pages. Completely unable to hold a socket open. So to give my starter a live feed, I had to move the site to a host that runs an always-on server — I landed back on Render — and stand up a small Node service whose entire personality is "keep one WebSocket to GE open, and tell the browser what it hears."

That's a real cost: I re-platformed a bread website for a starter widget. I'd do it again. The widget's the fun part, but the honest reason is that a static site had quietly become a place where I wanted live things to happen, and this was the push to build the room for them.

The browser never gets the keys

One rule I set before writing a line: the login token that reads my account can also, in the wrong hands, command my appliances. It is not going in anyone's browser. Ever.

So the server holds the token and the socket, and the browser only ever receives a scrubbed, read-only postcard: the starter's status, its temperature, when it's due. If someone views source on my home page, they get bread facts, not a key to my kitchen. That's the whole reason the server exists instead of doing it all in the page.

GE speaks in riddles, and temperature lives next door

With the login working, I asked the Digital Twin API for my devices. The documented endpoint 404'd; a neighbor of it answered. (You try the doors until one opens. This is most of software.) When my starter finally reported in, it said this:

{ "state": "cloud.smarthq.type.runstatus.off", "mode": "cloud.smarthq.type.mode.off", "starterMass": 0 }

Everything is a little URL. cloud.smarthq.type.runstatus.off is just "off" wearing a suit. Fine — I taught my code to take the last word and tidy it up.

The genuinely sneaky part: the temperature wasn't there. The Sidekick reports temperature from a separate service, in its own little message — { "fahrenheit": 70, "celsiusConverted": 21.1 } — that arrives on its own schedule. So the reading you see on the card is two different streams, stitched together server-side so neither one clobbers the other. Obvious in hindsight. Not obvious at 3 a.m.

The best bug I kept

When the Sidekick is switched off, my code first showed a blunt "Off." True, but sad — a starter is never really off. And it's not idle, either: when the Sidekick isn't running, my starter is sitting in my Brod & Taylor Sourdough Home, the other gadget, holding temperature.

So the status doesn't say "Off." It says "Resting in the Sourdough Home." Because that is literally where it is. Flip the Sidekick on and, within seconds, the same little line on my home page changes to "Rising." No refresh. It just knows.

That's my favorite kind of detail — the site telling the truth about a real object in my real kitchen, in words a person would actually use.

What it's doing right now

There's a slim ticker crawling across the top of the home page and a card lower down, both reading straight from the crock: rising or resting, the temperature to the degree, the day it's aiming to be ready. It updates itself. I did cut a detour along the way — I'd wired the oven in too, then pulled it; the oven's a story for another day, and the starter's the one that belongs on a bread site.

The lesson rhymes with the bread, which is the only reason I'll allow myself the sentence: the good version came from patience, from doing the boring part honestly, and from being willing to start over when the shape was wrong. A starter teaches you that on a slower clock. It turns out the software half of my life needed to hear it again.

The whole thing runs on The Starter — my shared code framework, named, of course, after the other one.