๐ŸŽ›๏ธ CLI to Get/Set/Stream Mac Hardware Outputs & Sensors Inputs

April 2, 2026 ยท View on GitHub

pip install mac-hardware-toys


This is a suite of composable CLI tools for getting, setting, and streaming/transforming raw Mac hardware sensor values.

  • sensors:
    accelerometer, microphone, lid-angle, ambient-light, gyroscope

  • transformers:
    volume-shift, frequency-shift, bandpass, metronome, heartbeat

  • outputs:
    speaker, keyboard-brightness, screen-brightness, visualizer, fan-speed


Most commands have basic args like --set ..., --json, --raw, making it easy to do useful things with your mac hardware.

  • ๐Ÿ’ก Flash your โŒจ๏ธ keyboard lights + play a sound when a background processes completes
  • โ˜€๏ธ Pulse your screen brightness in sync with detected ambient ๐ŸŽต music bpm / โค๏ธ your detected heartbeat via accelerometer
  • ๐Ÿ”ฌ Get/Set/Stream accelerometer+gyroscope+microphone/etc. data as simple --raw scalar values or --json, or...

All commands can also pipe in/out a a simple ๐ŸŽผ mono audio format.

๐ŸŽค read realtime sensor feeds represented as sine waves
๐ŸŽ›๏ธ mix/filter/transform those sine waves to shape them
๐Ÿ”Š emit piped realtime signal to speakers/any other hw output


Tip

Some truly wild things are possible now that you can pipe together anything on your Mac...
๐ŸŽท Share your craziest combos!


Flashing keyboard gif Flashing display gif

Screenshot 2026-02-20 at 11 19 36โ€ฏPM

Quickstart

pip install mac-hardware-toys
# or
uvx tool add mac-hardware-toys

Examples

# flash your screen according to your microphone input
microphone | screen-brightness

# play a sine wave tone based on your screen lid-angle
lid-angle | speaker

# flash the keyboard according to your heartbeat (keep your wrists on palm rests)
accelerometer | metronome | keyboard-brightness

# see more detail about any given signal by piping it into visualizer
microphone | visualizer
sine 1000 | visualizer
gyroscope | tee >(speaker) | visualizer

Tools

accelerometer

  • Purpose: read Apple SPU accelerometer and emit mono signal.
  • Args: --rate <hz> (<= 800), --axis x|y|z|mag, --raw.
  • Notes: requires root; when run from a terminal it auto-prompts via sudo.

ambient-light

  • Purpose: read ambient light sensor and emit tone mapped from low light to high light.
  • Default mapping: 500 Hz -> 5000 Hz and low volume -> high volume as light goes 0% -> 100%.
  • Args: --rate, --low-hz, --high-hz, --low-volume, --high-volume, --json.
  • Notes: requires root; when run from a terminal it auto-prompts via sudo.

lid-angle

  • Purpose: read lid angle sensor and emit tone mapped from lid closed to open.
  • Default mapping: 500 Hz -> 5000 Hz and low volume -> high volume as angle goes --angle-min -> --angle-max.
  • Args: --rate, --low-hz, --high-hz, --low-volume, --high-volume, --angle-min, --angle-max, --json.
  • Notes: requires root; when run from a terminal it auto-prompts via sudo.

gyroscope

  • Purpose: read fused orientation (accel+gyro, Mahony AHRS) and emit tone mapped from the selected orientation axis.
  • Default mapping: 500 Hz -> 5000 Hz and low volume -> high volume as selected axis angle maps to 0..360.
  • Args: --rate, --low-hz, --high-hz, --low-volume, --high-volume, --json, --axis roll|pitch|yaw, --decimate.
  • Notes: requires root; when run from a terminal it auto-prompts via sudo.
    • roll/pitch are absolute to gravity; yaw is relative and can drift without magnetometer.

microphone

  • Purpose: capture mono mic signal and emit stream.
  • Args: --rate <hz>, --block-size <frames>.

metronome [bpm]

  • Purpose: emit metronome pulses; with piped stdin it auto-detects/follows BPM.
  • Args: optional bpm, --rate (fixed mode), --pulse-ms, --tone-hz, --level, --accent-every, --accent-gain, --block-size, --count, --min-bpm, --max-bpm, --detect-low-hz, --detect-high-hz, --self-echo-ms, --follow, --debug, --raw.

bandpass <low_hz> <high_hz>

  • Purpose: realtime cascaded high/low-pass filter.
  • Args: positional cutoffs or --low/--high, --chunk-bytes, --raw --rate.

frequency-shift <factor>

  • Purpose: best-effort realtime frequency scaling, takes a scalar multiplier like 0.1~1000.
  • Args: factor, --chunk-bytes, --raw --rate.

volume-shift <gain>

  • Purpose: scalar amplitude gain.
  • Args: gain, --chunk-bytes, --raw --rate.

heartbeat

  • Purpose: emit BPM/confidence JSON lines from incoming signal (typically bandpassed). When piped onward, it passes the signal through on stdout and writes JSON to stderr.
  • Args: --interval, --window-seconds, --emit-final, --chunk-bytes, --raw --rate.

speaker

  • Purpose: play incoming stream on default output device.
  • Args: --device-rate, --block-size.

visualizer

  • Purpose: terminal waveform + level monitor.
  • Args: --fps, --window-seconds, --chunk-bytes, --raw --rate.

keyboard-brightness

  • Purpose: beat-follow keyboard backlight control.
  • Args: --send-hz, --fade-ms, --gain, --attack-ms, --release-ms, --baseline-ms, --decay-per-s, --debug, --as-root, --pulse, --on-time, --off-time, --set.
  • Notes:
    • --set=<0..100> without --pulse sets brightness and exits immediately (ignores stdin).
    • --pulse=<N> ignores stdin and pulses N times; --set controls pulse max brightness.

screen-brightness

  • Purpose: beat-follow display brightness control.
  • Args: --send-hz, --min-level, --max-level, --gain, --attack-ms, --release-ms, --baseline-ms, --decay-per-s, --debug, --no-restore, --pulse, --on-time, --off-time, --set.
  • Notes:
    • --set=<0..100> without --pulse sets display brightness and exits immediately (ignores stdin).
    • --pulse=<N> ignores stdin and pulses N times; --set controls pulse max brightness.

fan-speed

  • Purpose: signal-follow fan RPM control (both fans in sync by default; beat-alternating optional).
  • Args: --send-hz, --min-rpm, --max-rpm, --min-frac, --max-frac, --pulse-depth, --couple, --alternate, --input-map, --beat-threshold, --beat-hold-ms, --gain, --attack-ms, --release-ms, --baseline-ms, --decay-per-s, --debug, --no-restore.

Example Usage

Heartbeat from accelerometer:

accelerometer | bandpass 0.8 3 | heartbeat

Ambient light as signal source:

ambient-light | visualizer

Lid angle as JSONL:

lid-angle --json

Gyroscope fused orientation as JSONL:

gyroscope --axis roll --json

Music-reactive keyboard + speakers:

microphone --rate 44100 \
  | tee >(keyboard-brightness --send-hz 30 --fade-ms 20) \
  | volume-shift 0.8 \
  | speaker

Metronome to speakers:

metronome 120 | speaker

Auto-follow metronome from mic input, emits a metronome tone in sync with the beat of whatever audio is playing:

microphone | metronome | speaker

Auto-follow metronome from accelerometer, driving keyboard pulses:

accelerometer | metronome | keyboard-brightness

Metronome driving keyboard pulses:

metronome 120 | keyboard-brightness

Heartbeat telemetry while still driving keyboard brightness:

accelerometer | heartbeat | keyboard-brightness

Set keyboard backlight to 100% and exit:

keyboard-brightness --set=100

Pulse keyboard 5 times (1.2s on / 5.5s off) at 100%:

keyboard-brightness --pulse=5 --on-time=1.2 --off-time=5.5 --set=100

Set screen brightness to 40% and exit:

screen-brightness --set=40

Pulse screen brightness 3 times:

screen-brightness --pulse=3 --on-time=1.2 --off-time=5.5 --set=100

Metronome driving fan pulses:

metronome 120 | fan-speed --send-hz 4 --alternate --input-map beat --min-frac 0.30 --max-frac 0.70

Slow sine fan sweep (sync L/R):

sine 0.1 | fan-speed

One source, multiple sinks:

accelerometer \
  | bandpass 0.8 3 \
  | tee >(keyboard-brightness) \
  | frequency-shift 1000 \
  | volume-shift 0.8 \
  | tee >(speaker) \
  | visualizer

Notes

  • accelerometer requires root (AppleSPU HID access) and will auto-reexec through sudo by default.
  • ambient-light, lid-angle, and gyroscope do the same for AppleSPU HID access.
  • Set MSIG_AUTO_SUDO=0 to disable auto-reexec and only print rerun guidance on stderr.
  • microphone/speaker depend on sounddevice + PortAudio runtime.
  • Keyboard/display brightness tools need supported hardware/permissions.
  • keyboard-brightness uses the bundled Apple Silicon KBPulse binary at lib/KBPulse (arm64).
  • fan-speed uses AppleSMC private IOKit APIs on Apple Silicon; writing fan targets typically requires sudo.
  • frequency-shift is intentionally lightweight and artifact-prone at extreme factors.

Development Setup

git clone https://github.com/pirate/mac-hardware-toys
cd mac-hardware-toys

uv sync
source .venv/bin/activate

Stdio Audio Format

All stream tools read/write:

  • header: MSIG1 <sample_rate_hz>\n
  • payload: little-endian float32 mono samples

Most processors also support raw float32 input via --raw --rate <hz>.


Why?

It's fun. Here are some ideas to get started:

  • make your keyboard lights flash for security alerts using Security Growler
  • make your keyboard flash right before your display is about to sleep
  • make your keyboard flash on incoming email
  • make your keyboard flash to the beat of music
  • make your keyboard flash when your boss's iPhone comes within bluetooth range