This guide explains how to add support for a new USB display device.
Run the device creation wizard:
./sensorpanel device createFollow the prompts to generate a skeleton device profile.
A device profile implements the DeviceProfile interface defined in pkg/device/profile.go.
Key methods you need to implement:
| Method | Purpose |
|---|---|
ID() |
Unique identifier (e.g., "qtkeji") |
Matches(vid, pid) |
Return true if this profile supports the device |
Width(), Height() |
Display resolution |
ColorFormat() |
RGB565 or RGB888 |
ByteOrder() |
BigEndian or LittleEndian |
BlitCommand() |
Build command bytes to send image data |
BacklightCommand() |
Build command bytes for backlight control |
ConvertImage() |
Convert Go image to device pixel format |
Before implementing, you need to understand your device's USB protocol:
lsusb
# Find your device, note VID:PID
lsusb -d XXXX:YYYY -vUse Wireshark with USBPcap (Windows) or usbmon (Linux):
- Install Wireshark with USB capture support
- Run the manufacturer's software that drives the display
- Capture the USB traffic
- Analyze the packets
- Command structure: Most devices use SCSI CBW or custom bulk transfers
- Pixel format: RGB565 (16-bit) or RGB888 (24-bit)
- Byte order: Big-endian or little-endian
- Image transfer: How coordinates and dimensions are encoded
- Backlight control: Command bytes for brightness levels
See pkg/device/qtkeji.go for a complete example:
type QTKeJiProfile struct{}
func (p *QTKeJiProfile) ID() string { return "qtkeji" }
func (p *QTKeJiProfile) Matches(vid, pid uint16) bool {
return vid == 0x1908 && (pid == 0x0102 || pid == 0x0103)
}
func (p *QTKeJiProfile) BlitCommand(x, y, w, h int, dataLen int) []byte {
// Build SCSI CBW with vendor command
cmd := make([]byte, 16)
cmd[0] = 0xCD // Vendor prefix
// ... fill in command bytes
return BuildCBW(cmd, dataLen, DirOut)
}- Build:
go build . - List devices:
./sensorpanel device list - Select your device:
./sensorpanel device select - Test pattern:
./sensorpanel panel test - Run dashboard:
./sensorpanel run
Many USB displays use SCSI mass storage protocol with vendor-specific commands:
CBW (Command Block Wrapper):
- Signature: 0x55534243 ("USBC")
- Tag: Unique ID for matching response
- Data length: Size of image data
- Flags: Direction (0x00 = out, 0x80 = in)
- LUN: Usually 0
- Command length: 16 bytes
- Command: Vendor-specific bytes
Some devices use simpler bulk transfers:
- Send command header
- Send image data
- Wait for acknowledgment
- Fork the repository
- Add your profile in
pkg/device/ - Register it in
pkg/device/registry.go - Add yourself to CONTRIBUTORS.md
- Submit a pull request with:
- Device name and manufacturer
- Link to purchase (if available)
- Brief description of protocol
- Open an issue with the "new-device" label
- Include USB descriptor output (
lsusb -v) - Share any USB captures if possible