Linux busylight monitor that turns red when the microphone is in use and green when idle.
  • Python 60.3%
  • Shell 39.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-01 14:55:58 -07:00
packaging Autostart status indicator on login 2026-09-01 14:55:58 -07:00
scripts Autostart status indicator on login 2026-09-01 14:55:58 -07:00
src/busylight_monitor_app Autostart status indicator on login 2026-09-01 14:55:58 -07:00
.gitignore Add Debian package and desktop frontend 2026-09-01 11:48:27 -07:00
busylight-monitor.service Initial busylight monitor 2026-09-01 11:18:31 -07:00
busylight_monitor.py Add Debian package and desktop frontend 2026-09-01 11:48:27 -07:00
PACKAGING.md Autostart status indicator on login 2026-09-01 14:55:58 -07:00
pyproject.toml Autostart status indicator on login 2026-09-01 14:55:58 -07:00
QUICKSTART.md Autostart status indicator on login 2026-09-01 14:55:58 -07:00
README.md Autostart status indicator on login 2026-09-01 14:55:58 -07:00
requirements.txt Initial busylight monitor 2026-09-01 11:18:31 -07:00
SETUP.md Add Debian package and desktop frontend 2026-09-01 11:48:27 -07:00

Busylight Monitor

Drives a USB busylight red while you're on a call/in a meeting, and green the rest of the time — fully automatic, no per-app configuration.

Tested against a Plenom A/S Busylight Omega (USB 27bb:3bcf) — Plenom A/S is the company behind the Kuando brand, so this also works with other Kuando/EPOS Busylight devices, and with anything else supported by the busylight-for-humans Python library (Luxafor, Embrava Blynclight, MuteMe, ThingM Blink(1), and more).

Quickstart

For the fastest source-checkout setup path, follow QUICKSTART.md. For building an installable .deb, see PACKAGING.md.

How it works

busylight_monitor.py polls pactl list short source-outputs every 2 seconds. An application only opens a "source-output" stream while it's actively recording from the microphone, so this catches Zoom, Google Meet, Microsoft Teams, Slack huddles, or anything else that uses the mic — with no per-app setup. It then drives the light via the busylight-for-humans library:

  • Red — something currently has the mic open (you're on a call)
  • Green — idle

The Kuando/Omega protocol needs a periodic keepalive or the device turns itself off, so the script resends the current color every poll cycle rather than only on state changes.

Runs as a systemd --user service so it starts automatically on login and restarts itself if it ever crashes.

Requirements

  • Linux with PulseAudio or PipeWire (PipeWire's pipewire-pulse compatibility layer provides pactl, so either works)
  • Python 3.9+
  • pactl (pulseaudio-utils on Debian/Ubuntu-style systems)
  • A supported USB busylight

What's included

  • src/busylight_monitor_app/ - installable Python package with the monitor, CLI, GTK frontend, and top-panel status indicator.
  • busylight_monitor.py - compatibility launcher for source-checkout installs.
  • busylight-monitor.service - a source-checkout systemd --user unit for automatic startup on login.
  • packaging/ - Debian package build script, package service, and desktop entry.
  • requirements.txt - Python dependency list for the virtual environment.
  • scripts/check.sh - health report for files, dependencies, audio detection, hardware access, udev rules, and the user service.
  • scripts/repair.sh - common repair actions for the venv, udev rules, and systemd user service.
  • scripts/test_monitor_logic.py - hardware-free tests for microphone detection.
  • QUICKSTART.md - concise install and run instructions.
  • SETUP.md - fuller setup notes and troubleshooting.

Setup

1. Clone this repo

mkdir -p ~/applications
git clone https://repository.spitzerhome.com/david/Busylight-Linux.git ~/applications/Busylight-Linux
cd ~/applications/Busylight-Linux

(You can put it anywhere — just remember the path for the systemd unit in step 5.)

2. Create a virtual environment and install dependencies

python3 -m venv ~/.local/share/busylight-venv
source ~/.local/share/busylight-venv/bin/activate
pip install -r requirements.txt

3. Install the udev rule (lets the light work without root)

Still inside the venv:

busylight udev-rules -o 99-busylights.rules
sudo cp 99-busylights.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

Unplug and replug the light so the new permission takes effect.

4. Sanity-check the light on its own

busylight on red
busylight on green
busylight off

(These block the terminal while running — that's the keepalive loop. Press Ctrl+C to stop each one; the light turns off on exit. This is normal.)

5. Try the monitor by hand

~/.local/share/busylight-venv/bin/python ~/applications/Busylight-Linux/busylight_monitor.py

It should print [info] connected to busylight and idle -> green, with the light solid green. Join a call and confirm it prints ON CALL -> red and the light switches; end the call and confirm it goes back to green. Ctrl+C to stop.

6. Run it automatically as a background service

mkdir -p ~/.config/systemd/user

Create ~/.config/systemd/user/busylight-monitor.service (edit the ExecStart path if you cloned this repo somewhere other than ~/applications/Busylight-Linux):

[Unit]
Description=Busylight call/meeting indicator (red = on a call, green = idle)
After=default.target pipewire.service pulseaudio.service
Wants=pipewire.service

[Service]
ExecStart=%h/.local/share/busylight-venv/bin/python %h/applications/Busylight-Linux/busylight_monitor.py
Restart=on-failure
RestartSec=3

[Install]
WantedBy=default.target

Then enable it:

systemctl --user daemon-reload
systemctl --user enable --now busylight-monitor.service
systemctl --user status busylight-monitor.service

Look for active (running) in the status output. From now on it starts automatically on login.

APT repository

The latest package is published to the Forgejo Debian package registry. Add it to APT on Ubuntu/Debian-style systems with:

~/applications/Busylight-Linux/scripts/add-apt-repo.sh

Then install or upgrade with:

sudo apt install busylight-monitor

Debian package

Build a .deb for easier deployment to users:

cd ~/applications/Busylight-Linux
./packaging/deb/build-deb.sh

Install the generated package:

sudo apt install ./dist/busylight-monitor_0.2.2_amd64.deb

After installing, users can open Busylight Monitor from their application launcher or run:

busylight-monitor-gui

The package also autostarts the top-panel status indicator at graphical login. To start it immediately without logging out, open Busylight Status Indicator or run:

busylight-monitor-widget

See PACKAGING.md for build requirements, installed paths, and package commands. The package also migrates older CLI/source-checkout install leftovers that would conflict with the GUI package.

Light tests

The monitor service owns the USB light while it is running. Light test commands temporarily pause the user service, test the light, then restart the service:

busylight-monitor test-light red --seconds 5

Use --no-service-pause only when you know the monitor service is already stopped.

Health check and repair

Run the health check any time you want a quick report on whether the project is set up correctly:

~/applications/Busylight-Linux/scripts/check.sh

It checks the project files, git remote, virtual environment, Python import, unit tests, pactl, current mic stream detection, busylight hardware access, udev rules, and the systemd --user service. If the monitor service is active, the healthcheck treats HID open failed as expected because the service already owns the light. It exits nonzero if a required check fails.

To repair the common setup pieces in one pass from a source checkout:

~/applications/Busylight-Linux/scripts/repair.sh --all

In packaged installs, repair --all skips package-owned /opt files and tells you to use sudo apt install --reinstall busylight-monitor for package-level repairs.

You can also repair one area at a time:

~/applications/Busylight-Linux/scripts/repair.sh --venv
~/applications/Busylight-Linux/scripts/repair.sh --udev
~/applications/Busylight-Linux/scripts/repair.sh --service

--udev uses sudo and you still need to unplug/replug the light after udev rules are refreshed.

Everyday commands

systemctl --user status busylight-monitor.service      # is it running?
journalctl --user -u busylight-monitor.service -f       # live logs
systemctl --user disable --now busylight-monitor.service  # stop it for good
systemctl --user restart busylight-monitor.service       # restart it

Notes / known limitations

  • It goes red whenever an app has the mic stream open, which for most call apps stays true even if you mute yourself within that app. It reflects "in a call," not "currently unmuted."
  • Anything else that grabs the mic (dictation software, a voice recorder, a mic test) will also trigger red — it can't distinguish those from an actual call.
  • If the color never changes, run pactl list short source-outputs yourself during a real call — if it prints nothing, your setup routes audio differently and the detection logic in mic_in_use() needs adjusting.