Overview
A camera, a microphone, an accelerometer, a battery, a hinge‑angle sensor, per‑core CPU load: every one of them lives behind a different API, on a different platform, in a different SDK. sensortap discovers whatever a computer actually has and reads every one of them through the same schema. It's the layer that would have turned my earlier project, WinDuo, and Mac Duo before it, from a fresh reverse-engineering job per platform into a couple of adapter files.
Run sensortap list on my own laptop, a Dell G3 3779, and it reports 86 sensors across 16 kinds through 10 loaded backends, zero failing. Free and open source under MIT.
One Registry, Adapters That Don't Know About Each Other
A camera adapter talks to WinRT's `MediaCapture`. The hardware-telemetry adapter spawns a bundled .NET helper and reads LibreHardwareMonitor over a local named pipe with a per-user security descriptor. Neither shares a line of code with the other, and the registry never needs them to: each sensor family is one adapter, one file, registered through a normal Python entry point. The registry's job is narrow: load every adapter it finds, run discovery concurrently under one shared timeout so a slow backend can't stall the rest, de-duplicate and validate what comes back, and hand the caller one flat, typed list.
Every sensor, regardless of source, reports the same shape: a stable id, a closed-vocabulary kind, a unit, a sampling rate, and whether it's currently reachable. A contributor adding a new sensor family runs a Conformance_Check shipped inside the package itself, checkable against their own adapter with no access to sensortap's own repository.
A Real Bug the Compile Couldn't Catch
The .NET helper and the Python client authenticate over the pipe with a one-time token: the helper sends HELLO {token} as its first message, and Python rejects anything that doesn't match byte-for-byte. It compiled clean, zero warnings, and still failed every real handshake. .NET's default UTF-8 encoding writes a byte-order mark on a stream's first write, silently prepending three bytes to that exact line. The fix was writing the handshake as raw bytes, bypassing the encoding layer for that one message. Nothing in a static review or a green build would have surfaced it; only running the compiled helper against the real client did.
Enumeration Never Opens a Device
Listing sensors never turns on the camera light or triggers an OS permission prompt, even for camera and microphone entries. Reading or streaming one of those, or a touchpad's raw capacitive image, requires the caller to name that exact sensor id in a consent grant first. Grants live in memory only, are never written to disk, and end automatically. Motion, battery, radios, and hardware telemetry carry no personal information and need no grant at all.
What's Real, What's Not Built Yet
Nine Windows adapters ship today, all run against real hardware rather than mocked: WinRT motion, orientation, light, camera, and microphone; battery; Wi‑Fi and Bluetooth; touchpad; and the .NET helper bridge. Linux is designed into the architecture; nothing in the registry or the adapter interface is Windows-specific. No Linux backend exists yet, and it's the clearest open contribution. The hardware-telemetry helper is an optional, disclosed extra rather than bundled into the base install, so pip install sensortap alone stays small.