The Problem Every WFH Person Knows

You’re on a video call with a client. Things are going well. You’re presenting something important. And then — your kid walks in. Or your spouse pops their head around the door to ask what’s for dinner. Or worse, someone walks past in the background in… let’s say “casual home attire.”

The client says “it’s fine, no worries!” Your family member is mortified. You spend the next 30 seconds pretending nothing happened.

This has happened to me more times than I’d like to admit. Thankfully, no one on the other end ever cared. But my family? They cared. A lot.

I needed a way to tell them: “I’m on a call right now. Please don’t come in.”

The Inspiration

I follow Pankaj — who built a profit/loss indicator for Zerodha that shows green or red based on how his day trading is going. Simple concept: a light that communicates one piece of information at a glance.

That’s all I needed too. Red light = on a call. No light = coast is clear.

The Constraints

My first thought was the Microsoft Teams Graph API — the “proper” way to get your presence status. I raised a request with our IT team for API access.

I’m still waiting.

So, Plan B: read the Teams log files directly. Teams writes your presence status (Busy, Available, Do Not Disturb) to local log files in real time. No permissions needed. No tokens. No IT approval. Just tail a file.

For the bulb, I found the Philips WiZ smart bulbs — cheap, widely available, and controllable over your local network via plain UDP packets. No cloud. No bridge. No phone app middleman.

Building It with Claude

Now, like every responsible netizen in 2026, I had a Claude subscription sitting there with tokens to burn. I thought — why not actually build something useful with it? So I paired up with Claude Code and started hacking.

And honestly? That’s how OnAir came together. I described what I wanted, worked through the architecture decisions, debugged the cross-platform quirks, and shipped a working Rust binary — all through a conversation. It’s a weird and wonderful time to be a hobbyist developer.

What I Built

OnAir — a single Rust binary that:

  1. Tails Microsoft Teams’ local log file
  2. Detects when you join or leave a call
  3. Sends a UDP packet to your WiZ bulb to turn it red (or off)
  4. Serves a little web dashboard so you can see what’s happening

That’s it. The whole thing compiles to one ~6MB binary with zero runtime dependencies. No Docker, no Node, no Python virtualenv. Just download and run.

Why Rust?

I wanted something I could hand to anyone — “here, put this on your laptop” — without a 45-minute setup guide. Rust gives me:

  • Single binary — works on macOS, Windows, and Linux
  • No runtime — no JVM, no interpreter, no framework
  • Fast and light — uses practically no CPU or memory sitting in the background
  • Reliable — if it compiles, it generally just works

The Fun Technical Bits

Log Tailing Across Platforms

Teams logs differently on each OS. On macOS:

UserDataCrossCloudModule: CloudStateChanged: { availability: Busy, ... }

On Windows:

TaskbarBadgeServiceLegacy: ... GlyphBadge{"busy"} ...

So I have per-platform regex patterns that normalize both into the same internal state. The log watcher polls every 3 seconds, reads only new bytes since the last check, and fires a state transition when your presence changes.

The Grace Period

Back-to-back calls are common. Without a grace period, the bulb would go: red → off → red → off → red in quick succession. That’s annoying. So there’s a 10-second window — if you go busy again within 10 seconds of becoming available, the bulb stays red. Simple, but makes a huge difference in practice.

UDP Bulb Control

The WiZ protocol is surprisingly simple. Discovery is a broadcast, control is a JSON payload over UDP port 38899. No pairing, no auth. If you’re on the same network, you can talk to the bulb. The binary auto-discovers bulbs on your LAN at startup — if there’s only one, it picks it automatically.

The Dashboard

I built a tiny web UI at localhost:9876 — vanilla HTML/CSS/JS, no framework, embedded directly in the binary. It shows:

  • A live beacon that mirrors the bulb’s actual state
  • A console with the real-time event stream
  • Settings for work hours, colors, brightness, grace period
  • Manual override buttons (Force Red / Force Off / Auto)

The “Force Red” button is surprisingly useful for deep work sessions when you’re not on a call but don’t want to be disturbed either.

One Week In

I’ve been running this for a week now. It just… works. The bulb turns red when I join a call, turns off when I hang up, and my family has learned to check the light before walking in.

No more embarrassing walk-ins. No more “sorry, I didn’t know you were on a call.” Just a red light doing its job.

Try It

The project is open source: github.com/dannotes/onair

Grab a binary from the releases page, plug in a WiZ bulb, and you’re done. Works on macOS and Windows today (Linux is best-effort since Teams on Linux is… uncommon).

If you’re a fellow WFH person who’s tired of the “oh sorry, I didn’t know!” moment — give it a shot. Your family will thank you.