- Python 60.3%
- Shell 39.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| packaging | ||
| scripts | ||
| src/busylight_monitor_app | ||
| .gitignore | ||
| busylight-monitor.service | ||
| busylight_monitor.py | ||
| PACKAGING.md | ||
| pyproject.toml | ||
| QUICKSTART.md | ||
| README.md | ||
| requirements.txt | ||
| SETUP.md | ||
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-pulsecompatibility layer providespactl, so either works) - Python 3.9+
pactl(pulseaudio-utilson 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-checkoutsystemd --userunit 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-outputsyourself during a real call — if it prints nothing, your setup routes audio differently and the detection logic inmic_in_use()needs adjusting.