https://github.com/oae/sensorpanel
Turn cheap USB LCD panels into pro-grade hardware monitors. Real sensors, custom themes, one binary.
https://github.com/oae/sensorpanel
cli cpu-monitor cross-platform dashboard golang gpu-monitor hardware-monitor lcd-display linux macos nixos react real-time sensors system-monitor temperature-monitor typescript usb-lcd windows
Last synced: 8 days ago
JSON representation
Turn cheap USB LCD panels into pro-grade hardware monitors. Real sensors, custom themes, one binary.
- Host: GitHub
- URL: https://github.com/oae/sensorpanel
- Owner: oae
- License: mit
- Created: 2026-01-30T16:59:24.000Z (6 months ago)
- Default Branch: master
- Last Pushed: 2026-06-27T15:34:05.000Z (27 days ago)
- Last Synced: 2026-06-27T17:17:29.866Z (27 days ago)
- Topics: cli, cpu-monitor, cross-platform, dashboard, golang, gpu-monitor, hardware-monitor, lcd-display, linux, macos, nixos, react, real-time, sensors, system-monitor, temperature-monitor, typescript, usb-lcd, windows
- Language: Go
- Size: 783 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# SensorPanel
[](https://github.com/oae/sensorpanel/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/oae/sensorpanel)
[](https://opensource.org/licenses/MIT)
A cross-platform CLI tool for driving USB LCD displays as real-time system monitoring dashboards.

## Features
- **Multi-device support** - Modular device profiles for different USB displays
- **Easy device contribution** - Interactive wizard to add support for new panels
- **Real-time monitoring** - CPU, GPU (NVIDIA/AMD), RAM, disk, and network stats
- **Media display modes** - Static images, animated GIFs, and a now-playing dashboard
- **Music dashboard** - Cover art, song metadata, progress waveform, and synchronized lyrics
- **Regional USB updates** - Sends only changed rectangles when the panel protocol supports it
- **Dynamic sensor config** - Enable/disable sensors and configure options at runtime
- **Web-based themes** - Create custom themes using React + TypeScript
- **TypeScript SDK** - React hooks for easy theme development with hot reload
- **Single-command dev** - One command starts everything for theme development
- **Headless rendering** - Auto-downloads Chrome for Testing to render themes
- **Cross-platform** - Works on Linux, macOS, and Windows
- **Autostart service** - Install as system service on all platforms
- **NixOS support** - Flake with module, udev rules, and systemd service
## Quick Start
### 1. Build
```bash
# Install Mage (recommended build tool)
go install github.com/magefile/mage@latest
# Build with Mage
mage build
# Or directly with Go
go build .
# Or with Nix
nix build
```
### 2. Select your display
```bash
./sensorpanel device list # See available devices
./sensorpanel device select # Interactive selection
```
### 3. Run the dashboard
```bash
# With built-in renderer
./sensorpanel run
# Play an animated GIF instead of sensor data
./sensorpanel run --gif /path/to/animation.gif
# URLs are also supported
./sensorpanel run --gif https://media.tenor.com/j8dwT9wdyc8AAAAi/evernight-anime.gif
# Display a static PNG, JPEG, or GIF from a file or URL
./sensorpanel run --image /path/to/wallpaper.png
# Display the active song with artwork, progress waveform, and synchronized lyrics
./sensorpanel run --music
# With sensor options
./sensorpanel run --opt disk.mounts=/,/home --opt network.interface=eth*
# Or create and use a custom theme
./sensorpanel theme create my-theme
./sensorpanel theme select my-theme
./sensorpanel run
```
### 4. (Optional) Install as autostart service
```bash
# Install to start on login
./sensorpanel service install --opt disk.mounts=/
# Start now
./sensorpanel service start
# Check status
./sensorpanel service status
```
## Supported Devices
SensorPanel uses a modular device profile system. Currently supported:
| Device | Resolution | Color Format | Notes |
|--------|------------|--------------|-------|
| QTKeJi/AIDA64 USB Display | 480x320 | RGB565 BE | VID 0x1908 |
| Generic AX206-based frames | Various | RGB565 | GEMBIRD, Pearl, Coby, etc. |
**Don't see your device?** Run `sensorpanel device create` to add support for it!
## Commands
### Run Dashboard
```bash
sensorpanel run [flags]
Flags:
-i, --interval float Update interval in seconds (default 1.0)
-b, --brightness int Backlight brightness 0-7 (default 7)
-s, --sensors strings Sensors to enable (e.g., cpu,memory,disk). Default: all
-x, --exclude strings Sensors to exclude (e.g., network,nvidia_gpu)
-o, --opt strings Sensor options (e.g., disk.mounts=/,/home)
--gif string Play an animated GIF file or URL instead of sensor data
--image string Display a PNG, JPEG, or GIF file or URL instead of sensor data
--music Show now-playing music dashboard instead of sensor data
```
The music dashboard currently supports Linux MPRIS players such as Spotify,
VLC, and compatible browser players. It requires `playerctl`. Synchronized
lyrics are loaded from LRCLIB when available.
Lyrics are cached locally for faster reuse and fewer network requests.
See [Media and Music Modes](docs/media-modes.md) for format support, layout
behavior, requirements, lyrics behavior, and service setup.
### Sensor Options
Configure sensor behavior with `--opt` flags or in config.json:
```bash
# Show available sensor options
sensorpanel sensor opts
# Examples
sensorpanel run --opt disk.mounts=/,/home --opt network.interface=eth*
```
| Option | Type | Description |
|--------|------|-------------|
| `disk.mounts` | `[]string` | Disk mount points to monitor |
| `network.interface` | `string` | Network interface filter (supports `*` wildcard) |
| `nvidia_gpu.smi_path` | `string` | Custom path to nvidia-smi binary |
### Device Management
```bash
sensorpanel device list # List connected USB displays
sensorpanel device select # Interactive device selection
sensorpanel device info # Show current device and profile info
sensorpanel device create # Generate code for new device support
sensorpanel device reset # Reset to defaults
```
### Theme Management
```bash
sensorpanel theme list # List installed themes
sensorpanel theme create # Create from React+TypeScript template
sensorpanel theme select # Set active theme
sensorpanel theme dev [name] # Start dev server with hot reload
sensorpanel theme build [name] # Build theme for production
sensorpanel theme preview [name] # Open in browser
sensorpanel theme delete # Remove theme
sensorpanel theme path # Show themes directory
sensorpanel theme sdk update [name] # Update SDK in existing theme
sensorpanel theme browser install # Download Chrome for Testing
sensorpanel theme browser status # Check browser availability
sensorpanel theme browser remove # Remove cached browser
```
### Panel Control
```bash
sensorpanel panel status # Check if panel is connected
sensorpanel panel test # Display test pattern
sensorpanel panel on # Turn backlight on
sensorpanel panel off # Turn backlight off
sensorpanel panel brightness 5 # Set brightness (0-7)
```
### Sensor Management
```bash
sensorpanel sensor list # List all registered sensors
sensorpanel sensor list -a # List only available sensors on this system
sensorpanel sensor opts # List available sensor options
sensorpanel sensor types # Generate TypeScript types for all sensors
sensorpanel sensor types -o types.ts # Output to file
sensorpanel sensor create # Interactive wizard to create a new sensor
```
### Service Management (Autostart)
```bash
sensorpanel service install # Install as autostart service
sensorpanel service install --opt disk.mounts=/ # With sensor options
sensorpanel service install --music # Start in now-playing mode
sensorpanel service install --gif https://example.com/animation.gif
sensorpanel service install --image /path/to/wallpaper.png
sensorpanel service uninstall # Remove autostart service
sensorpanel service start # Start the service now
sensorpanel service stop # Stop the service
sensorpanel service status # Show service status
sensorpanel service logs # View service logs
sensorpanel service logs -f # Follow logs in real-time
```
Cross-platform support:
- **Linux**: systemd user service (`~/.config/systemd/user/`)
- **macOS**: launchd LaunchAgent (`~/Library/LaunchAgents/`)
- **Windows**: Startup folder + Registry
Re-running `service install` updates the existing service definition. Stop and
start the service afterward to apply the new command line.
### Other Commands
```bash
sensorpanel benchmark # Measure full-frame FPS
sensorpanel benchmark --region-width 64 --region-height 32 # Measure regional FPS
sensorpanel benchmark --animation --target-fps 60 # Test moving regional updates
sensorpanel prune # Remove config and cache (keeps themes)
sensorpanel prune --all # Also remove themes
```
### Rendering performance
SensorPanel automatically uses regional updates for run modes when the selected
USB display supports rectangular writes. The first frame is sent as a full
frame. Later frames are compared against the previous RGB565 buffer, unchanged
frames are skipped, and changed pixels are grouped into cost-aware rectangular
updates. If a regional write fails, SensorPanel falls back to full-frame writes.
Regional updates help most when the layout is mostly static and only small
areas change, such as numeric sensor values, playback progress, or a clock.
They help least when large parts of the screen change every frame, such as
full-screen GIF/video-style animation, large gradients, or moving backgrounds.
The benchmark command can measure the real device instead of relying on theory:
```bash
# Full-frame transfer speed
sensorpanel benchmark
# Raw rectangular write speed for a centered 64x32 area
sensorpanel benchmark --region-width 64 --region-height 32 --frames 100
# End-to-end dirty-region animation test
sensorpanel benchmark --animation --region-width 64 --region-height 32 --target-fps 60
```
On USB full-speed panels such as the QTKeJi/AIDA64 480×320 display, small
regions can update much faster than full frames, but large full-screen changes
are still limited by USB bandwidth and the panel's update behavior.
## Adding Device Support
Got a USB display that isn't supported yet? Adding support is easy:
```bash
# Run the interactive wizard
./sensorpanel device create
```
This prompts you for:
- Device name and ID
- USB Vendor ID and Product ID
- Display resolution
- Color format (RGB565/RGB888) and byte order
- Backlight levels
It generates a skeleton Go file in `pkg/device/` that you can customize.
See [docs/adding-devices.md](docs/adding-devices.md) for detailed protocol research tips.
## Adding Custom Sensors
SensorPanel uses a modular sensor provider system. Each sensor is a Go provider that implements the `sensors.Provider` interface.
### Built-in Sensors
| Sensor | Platforms | Description |
|--------|-----------|-------------|
| `cpu` | Linux | CPU load, temperature, frequency |
| `memory` | Linux | RAM usage |
| `disk` | Linux, macOS, Windows | Disk usage per mount point |
| `network` | Linux | Network interface statistics |
| `nvidia_gpu` | Linux | NVIDIA GPU via nvidia-smi |
| `amd_gpu` | Linux | AMD GPU via sysfs |
### Create a Custom Sensor
```bash
# Run the interactive wizard
./sensorpanel sensor create
```
This prompts you for:
- Sensor ID and name
- Target platform (Linux, macOS, Windows, or all)
- Category (system, gpu, storage, network, power)
- Field definitions with types and units
It generates a skeleton Go file in `pkg/sensors/` that you can customize.
### Adding Platform-Specific Implementations
If a sensor already exists but only for certain platforms, running `sensor create` with the same ID will prompt you to add an implementation for a different platform:
```bash
./sensorpanel sensor create
Sensor ID: cpu
Sensor 'cpu' already exists for platforms: linux
Which platform would you like to add?
1. linux
2. darwin (macOS)
3. windows
```
### Update TypeScript Types
After adding or modifying sensors, regenerate the TypeScript types for themes:
```bash
./sensorpanel sensor types -o path/to/theme/lib/sensorpanel/types.ts
```
## Theme Development
Themes are React + TypeScript applications that receive sensor data via WebSocket. A bundled SDK provides React hooks for easy integration.
### Create a theme
```bash
sensorpanel theme create my-theme
```
### Development workflow (single command!)
```bash
# Start everything with one command:
sensorpanel theme dev my-theme
# With sensor options:
sensorpanel theme dev my-theme --opt disk.mounts=/ --opt network.interface=eth*
# This automatically:
# - Detects your package manager (npm/yarn/pnpm/bun)
# - Installs dependencies if needed
# - Starts WebSocket sensor server (port 19847)
# - Starts Vite dev server with HMR (port 15173)
# - Opens your browser
```
### Using the SDK
```tsx
import { useSensorData, useConnectionStatus, formatRate } from "../lib/sensorpanel";
function App() {
const data = useSensorData();
const status = useConnectionStatus();
if (status !== "connected" || !data) {
return
Connecting...;
}
return (
CPU: {data.cpu.load.toFixed(0)}%
GPU: {data.gpu.temperature?.toFixed(0) ?? "--"}°C
RAM: {data.memory.percent.toFixed(0)}%
);
}
```
### Build and use
```bash
sensorpanel theme build my-theme
sensorpanel theme select my-theme
sensorpanel run
```
See [docs/creating-themes.md](docs/creating-themes.md) for the full guide.
## NixOS Installation
### Add to your flake.nix
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
sensorpanel.url = "github:alperen/sensorpanel";
};
outputs = { self, nixpkgs, sensorpanel, ... }: {
nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
sensorpanel.nixosModules.default
{
services.sensorpanel = {
enable = true;
interval = 1.0;
brightness = 7;
theme = "my-theme"; # or null for built-in renderer
};
}
];
};
};
}
```
### Module options
```nix
services.sensorpanel = {
enable = true;
interval = 1.0; # Update interval in seconds
brightness = 7; # Backlight brightness (0-7)
theme = null; # Theme name or null for built-in
sensorOptions = { # Sensor-specific options
"disk.mounts" = [ "/" "/home" ];
"network.interface" = "eth*";
};
user = "sensorpanel"; # Service user
group = "sensorpanel"; # Service group (for USB access)
};
```
## File Locations
| Type | Path |
|------|------|
| Config | `~/.config/sensorpanel/config.json` |
| Themes | `~/.local/share/sensorpanel/themes/` |
| Browser cache | `~/.cache/sensorpanel/browser/` |
## Architecture
### Device Profiles
Each USB display is supported via a device profile that implements:
```go
type DeviceProfile interface {
ID() string // "qtkeji", "my-device"
Name() string // Human-readable name
Matches(vid, pid uint16) bool // USB device matching
Width() int // Display width
Height() int // Display height
ColorFormat() ColorFormat // RGB565 or RGB888
ByteOrder() ByteOrder // BigEndian or LittleEndian
BlitCommand(x, y, w, h, len int) []byte // Build display command
BacklightCommand(level int) []byte // Build backlight command
ConvertImage(img image.Image) []byte // Convert to device format
}
```
### Sensor Sources (Linux)
| Metric | Source |
|--------|--------|
| CPU Load | `/proc/stat` |
| CPU Temp | `/sys/class/hwmon/*/temp*_input` |
| CPU Freq | `/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq` |
| GPU (NVIDIA) | `nvidia-smi` |
| GPU (AMD) | `/sys/class/drm/card*/device/` |
| RAM | `/proc/meminfo` |
| Disk | `syscall.Statfs` |
| Network | `/proc/net/dev` |
## Troubleshooting
### Device not found
```bash
# List USB devices
lsusb
# Check if sensorpanel detects it
./sensorpanel device list
```
If your device shows in `lsusb` but not in sensorpanel, it may need a new device profile. Run `sensorpanel device create` to add support.
### Permission denied
Create a udev rule for your device:
```bash
# Replace XXXX and YYYY with your device's VID and PID
sudo tee /etc/udev/rules.d/99-sensorpanel.rules << EOF
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="YYYY", MODE="0666"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger
```
On NixOS with the module, udev rules are set up automatically for known devices.
### Theme not rendering
```bash
# Check if browser is installed
sensorpanel theme browser status
# Install browser if needed
sensorpanel theme browser install
# Check theme is built
ls ~/.local/share/sensorpanel/themes/my-theme/dist/
```
### No GPU stats
```bash
# NVIDIA: Check nvidia-smi works
nvidia-smi
# AMD: Check sysfs
ls /sys/class/drm/card*/device/gpu_busy_percent
```
## Development with Mage
SensorPanel uses [Mage](https://magefile.org/) as its build tool. Install it with:
```bash
go install github.com/magefile/mage@latest
```
### Available Targets
```bash
mage -l # List all targets
mage build # Build for current platform (default)
mage install # Build and install to GOPATH/bin
mage test # Run all tests
mage vet # Run go vet
mage lint # Run golangci-lint
mage check # Run all checks (vet, test, lint)
mage clean # Remove build artifacts
mage release # Cross-compile for all platforms (dist/)
mage dev # Build and run the dashboard
mage devTheme # Build and start theme dev mode
```
## Testing
SensorPanel has comprehensive unit tests with good coverage across all core packages.
### Running Tests
```bash
# Run all tests
go test ./...
# Run with verbose output
go test -v ./...
# Run with race detector
go test -race ./...
# Run with coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out # Summary by function
go tool cover -html=coverage.out # Interactive HTML report
```
### Coverage by Package
| Package | Coverage | Description |
|---------|----------|-------------|
| `pkg/device` | ~99% | Device profiles and registry |
| `pkg/server` | ~95% | WebSocket server for themes |
| `pkg/paths` | ~77% | XDG directory handling |
| `pkg/sensors` | ~57% | System sensor collection |
| `pkg/panel` | ~50% | USB panel protocol (hardware-dependent) |
| `pkg/config` | ~40% | Configuration and device discovery |
| `pkg/theme` | ~34% | Theme management and building |
Some packages have lower coverage because they interact with hardware (USB devices), external processes (Chromium), or the filesystem in ways that are difficult to test in isolation.
## Contributing
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
### Ways to contribute
- **Add device support** - Run `sensorpanel device create` and submit a PR
- **Create themes** - Share your themes with the community
- **Improve docs** - Help others get started
- **Fix bugs** - Check the issue tracker
## License
MIT License - See LICENSE file for details.