SensorPanel

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
- 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
# 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
./sensorpanel device list # See available devices
./sensorpanel device select # Interactive selection
3. Run the dashboard
# With built-in renderer
./sensorpanel run
# 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
# 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
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)
Sensor Options
Configure sensor behavior with --opt flags or in config.json:
# 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
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
sensorpanel theme list # List installed themes
sensorpanel theme create <name> # Create from React+TypeScript template
sensorpanel theme select <name> # 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 <name> # 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
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
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)
sensorpanel service install # Install as autostart service
sensorpanel service install --opt disk.mounts=/ # With sensor options
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
Other Commands
sensorpanel benchmark # Measure FPS performance
sensorpanel prune # Remove config and cache (keeps themes)
sensorpanel prune --all # Also remove themes
Adding Device Support
Got a USB display that isn't supported yet? Adding support is easy:
# 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 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
# 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.
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:
./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:
./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
sensorpanel theme create my-theme
Development workflow (single command!)
# 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
import { useSensorData, useConnectionStatus, formatRate } from "../lib/sensorpanel";
function App() {
const data = useSensorData();
const status = useConnectionStatus();
if (status !== "connected" || !data) {
return <div>Connecting...</div>;
}
return (
<div>
<p>CPU: {data.cpu.load.toFixed(0)}%</p>
<p>GPU: {data.gpu.temperature?.toFixed(0) ?? "--"}°C</p>
<p>RAM: {data.memory.percent.toFixed(0)}%</p>
</div>
);
}
Build and use
sensorpanel theme build my-theme
sensorpanel theme select my-theme
sensorpanel run
See docs/creating-themes.md for the full guide.
NixOS Installation
Add to your flake.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
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:
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
# 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:
# 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
# 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
# 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 as its build tool. Install it with:
go install github.com/magefile/mage@latest
Available Targets
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
# 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 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.