KPI仪表盘

kpidash是一款运行于Raspberry Pi 5的全屏KPI仪表盘,通过LVGL和Redis实时展示多台Linux/Windows客户端的健康状态、遥测数据、活动和仓库状态。

  • by kenhia
  • C
  • 本地部署
  • 更新于
在 GitHub 查看 kenhia/kpidash

使用说明

kpidash

A fullscreen KPI dashboard for Raspberry Pi 5, built with LVGL and Redis. Displays real-time health, telemetry, activities, repo status, and fortune messages for multiple client machines — Linux and Windows.

Note: this project is centered around building the dashboard I want; it's not a "general purpose dashboard creation tool". I had an RPi 5 and a spare 4K monitor and specific information I wanted to be able to glance at.

That said, I do think there is some goodness here for others wanting to do something similar...the decision to put a Redis server on the RPi and use that for communication is a big win for me.

Dashboard layout

┌─────────────────────────────────────────────┐
│  Client cards (health LED, CPU/RAM/disk)    │
├────────────────────┬────────────────────────┤
│  Activities        │  Repo Status           │
├────────────────────┴────────────────────────┤
│  Fortune                                    │
└─────────────────────────────────────────────┘

Quick start

1. Clone

git clone --recurse-submodules <repo-url>
cd kpidash

2. Cross-compile for Pi 5

# Install cross toolchain (Ubuntu/Debian)
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu cmake pkg-config

# Sync Pi sysroot (replace rpi53 with your Pi hostname/IP)
SYSROOT=$HOME/pi5-sysroot && mkdir -p $SYSROOT
rsync -avz --rsync-path="sudo rsync" ken@rpi53:/lib/aarch64-linux-gnu $SYSROOT/lib/
rsync -avz --rsync-path="sudo rsync" ken@rpi53:/usr/lib/aarch64-linux-gnu $SYSROOT/usr/lib/
rsync -avz ken@rpi53:/usr/include $SYSROOT/usr/

# Build
cmake -B build-pi -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-toolchain.cmake
cmake --build build-pi --target kpidash -j$(nproc)

# Deploy
rsync -az build-pi/kpidash ken@rpi53:~/kpidash

3. Run on Pi 5

# DRM requires root (or video group membership); -E preserves REDISCLI_AUTH.
# On rpi53 the password comes from the host's one copy rather than your shell:
set -a; . /etc/khomelab/secrets.env; set +a     # needs group khomelab
sudo -E ./kpidash

Running it by hand like this is for debugging. The installed service reads the same file itself — see ops/rpi53/dashboard/.

4. Start a client daemon (Linux or Windows)

cd clients/kpidash-client
uv sync                       # Python 3.13 venv, see .python-version
uv run kpidash-client daemon start

See clients/kpidash-client/README.md for config file setup.


Configuration (dashboard)

Environment Variable Default Description
KPIDASH_REDIS_HOST 127.0.0.1 Redis host
KPIDASH_REDIS_PORT 6379 Redis port
REDISCLI_AUTH (none) Redis password — must be in env when using sudo -E. One copy per host in /etc/khomelab/secrets.env; the service reads it with EnvironmentFile=
KPIDASH_DRM_DEV /dev/dri/card1 DRM device (card1 = vc4 GPU on Pi 5)
KPIDASH_MAX_CLIENTS 16 Max tracked clients
KPIDASH_ACTIVITY_MAX 10 Max activities shown
KPIDASH_LOG_FILE /var/log/kpidash/kpidash.log Log path written to Redis
KPIDASH_STATE_FILE /var/lib/kpidash/admitted Hosts that have published at least once, one per line. Loaded at startup so a host that is down across a restart still shows a red card instead of no card; written only when the set grows. Missing or corrupt = start empty
KPIDASH_PRIORITY_CLIENTS (none) Comma-separated hostnames; displayed first in listed order, never evicted from registry

Native unit tests (no hardware required)

just check

Equivalent to, and the project's CI gate:

cmake -B build-tests -DTESTS_ONLY=ON
cmake --build build-tests
ctest --test-dir build-tests --output-on-failure

TESTS_ONLY=ON skips the dashboard binary and its LVGL/DRM dependencies, so this needs no Pi, no sysroot and no submodule checkout.


Python clients

Package Purpose Docs
clients/kpidash-client Telemetry daemon + CLI (Linux, Windows) README
clients/kpidash-mcp MCP server for AI agent activity reporting README

Both packages are managed with uv and pinned to Python 3.13.


Project structure

kpidash/
├── CMakeLists.txt              # CMake 3.22+, hiredis, cJSON, libdrm, LVGL
├── lv_conf.h                   # LVGL configuration
├── cmake/
│   └── aarch64-toolchain.cmake # Cross-compile toolchain for Pi 5
├── fonts/
│   ├── generate.sh             # lv_font_conv: Montserrat Bold 14-48px + NF icons
│   ├── lv_font_custom.h        # Extern declarations for generated bold fonts
│   ├── lv_font_montserrat_bold_*.c  # Generated font sources (7 sizes)
│   └── ttf/                    # Source TTF files (Montserrat-Bold, SymbolsNerdFont)
├── src/
│   ├── main.c                  # Entry: config, LVGL init, DRM, poll timers
│   ├── config.{h,c}            # Environment variable parsing
│   ├── registry.{h,c}          # In-memory client state (mutex-protected)
│   ├── redis.{h,c}             # hiredis poll cycle + cJSON parsing
│   ├── status.{h,c}            # Status message FIFO queue
│   ├── fortune.{h,c}           # fortune popen + pushed-fortune override
│   ├── ui.{h,c}                # Screen layout + Redis error overlay
│   ├── protocol.h              # Redis key macros + compile-time constants
│   └── widgets/
│       ├── client_card.{h,c}   # Per-client arc gauge card (CPU/RAM/GPU/disks)
│       ├── activities.{h,c}    # Activity table with live elapsed timers
│       ├── repo_status.{h,c}   # Repo card grid (branch/dirty/age indicators)
│       ├── fortune.{h,c}       # Fortune text label
│       ├── status_bar.{h,c}    # Bottom status bar
│       ├── dev_grid.{h,c}      # Pixel grid overlay (dev command)
│       ├── dev_textsize.{h,c}  # Font size reference panel (dev command)
│       └── dev_graph.{h,c}     # 5-series time-series chart (dev command)
├── tests/
│   ├── test_config.c           # ctest: config env-var parsing
│   └── test_redis_json.c       # ctest: Redis JSON parsing helpers
├── clients/
│   ├── kpidash-client/         # Python 3.13 daemon + CLI
│   └── kpidash-mcp/            # Python 3.13 MCP server
├── scripts/
│   └── load_test.py            # 8-client concurrent write stress test
├── lib/
│   └── lvgl/                   # LVGL v9.2.2 (git submodule)
├── sprints/                    # One record per PR-sized unit of work
│   ├── 001-mvp-dashboard/      # Early sprints: spec, plan, tasks, contracts
│   ├── 013-service-card-polish.md  # Later sprints: one narrative file
│   └── planning/roadmap.md     # Now / Next / Later
└── docs/
    ├── ARCHITECTURE.md         # System design and component diagram
    ├── CLIENT-PROTOCOL.md      # Redis key/value schema reference
    └── HANDOFF-CROSSCOMPILE.md # Cross-compilation guide

Requirements

  • Pi 5: Debian 13 (Trixie), Redis 7.x, fortune package
  • Pi packages: libdrm-dev libpng-dev libcjson-dev libhiredis-dev libfreetype-dev libinput-dev libxkbcommon-dev redis-server fortune
  • Cross-compile host: Ubuntu 22.04+ x86_64, GCC aarch64 toolchain, CMake 3.22+
  • Python clients: Python 3.13 via uv