From 8b0eb42fec0ab07d102b2c9a54e35b952a39ec40 Mon Sep 17 00:00:00 2001 From: Jeancarlo Date: Fri, 8 May 2026 01:14:17 -0300 Subject: [PATCH] add MCP developer tool with multi-unit support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First developer tool for the XDJ-100SX project. Connects Claude Code directly to the Pi over SSH — push skin files, take screenshots, restart Mixxx, flash Pico firmware, and more without leaving the editor. Available MCP tools: - run_command, read_file, write_file, list_files - push_skin, pull_skin, push_skin_file, pull_skin_file - push_midi, pull_midi - take_screenshot, navigate_panel - restart_mixxx - check (preflight: SSH, Mixxx, Pico, audio) - pico_bootloader, pico_flash - discover_units — scan network for all reachable XDJ Pi units - select_unit — switch active connection mid-session (multi-unit support) Also adds --about flag and TUI About modal with authors and credits, and fixes scrolling/close behavior on Help and About modals. By: Jeancarlo Cardoso de Faria Filho (jaianlab) --- README.md | 2 + tools/README.md | 165 ++ tools/SKIN_DEV.md | 358 ++++ tools/xdj-pi-dev.py | 2540 +++++++++++++++++++++++++++ tools/xdj_pi_dev/__init__.py | 1 + tools/xdj_pi_dev/_terminal.py | 158 ++ tools/xdj_pi_dev/backup.py | 449 +++++ tools/xdj_pi_dev/config.py | 127 ++ tools/xdj_pi_dev/image_utils.py | 127 ++ tools/xdj_pi_dev/messages.py | 99 ++ tools/xdj_pi_dev/midi.py | 126 ++ tools/xdj_pi_dev/pico_tools.py | 453 +++++ tools/xdj_pi_dev/setup_cmds.py | 217 +++ tools/xdj_pi_dev/signal_analyzer.py | 906 ++++++++++ tools/xdj_pi_dev/watch.py | 267 +++ 15 files changed, 5995 insertions(+) create mode 100644 tools/README.md create mode 100644 tools/SKIN_DEV.md create mode 100644 tools/xdj-pi-dev.py create mode 100644 tools/xdj_pi_dev/__init__.py create mode 100644 tools/xdj_pi_dev/_terminal.py create mode 100644 tools/xdj_pi_dev/backup.py create mode 100644 tools/xdj_pi_dev/config.py create mode 100644 tools/xdj_pi_dev/image_utils.py create mode 100644 tools/xdj_pi_dev/messages.py create mode 100644 tools/xdj_pi_dev/midi.py create mode 100644 tools/xdj_pi_dev/pico_tools.py create mode 100644 tools/xdj_pi_dev/setup_cmds.py create mode 100644 tools/xdj_pi_dev/signal_analyzer.py create mode 100644 tools/xdj_pi_dev/watch.py diff --git a/README.md b/README.md index df6fe44..d476776 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,5 @@ Note it only works with the Raspberry Pi 3B+ 2025 Marc Monka 2026 Markus Golec + +2026 Jeancarlo Cardoso de Faria Filho (jaianlab) — Raspberry Pi Pico port, MCP developer tool diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..876fdbd --- /dev/null +++ b/tools/README.md @@ -0,0 +1,165 @@ +# XDJ-100SX Developer Tool + +Claude Code MCP server + CLI + TUI for the XDJ-100SX Pi system. +Push skin files, take screenshots, flash firmware, and manage the Pi — all from your editor. + +--- + +## Requirements + +```bash +pip install paramiko watchdog textual +``` + +--- + +## Quick start + +```bash +python3 tools/xdj-pi-dev.py --check # verify connection + environment +python3 tools/xdj-pi-dev.py --status # live Pi + Mixxx status +python3 tools/xdj-pi-dev.py --ui # interactive TUI +python3 tools/xdj-pi-dev.py --about # authors & credits +python3 tools/xdj-pi-dev.py --help # full command reference +``` + +--- + +## Connection + +The tool tries these in order: + +1. `--host` flag +2. `XDJ_HOST` environment variable +3. `XDJ100SX.local` — mDNS, works on any network (WiFi or LAN) +4. `192.168.10.2` — static IP fallback for direct cable + +### Direct cable (no router) + +One-time setup on your machine: + +```bash +# macOS +sudo ifconfig en0 alias 192.168.10.1 255.255.255.0 + +# Linux +sudo ip addr add 192.168.10.1/24 dev eth0 + +# Windows (run as Administrator) +netsh interface ip set address "Ethernet" static 192.168.10.1 255.255.255.0 +``` + +Then on the Pi (once): + +```bash +python3 tools/xdj-pi-dev.py --setup-pi-dhcp +``` + +After that the Pi hands out IPs automatically — no manual config needed on any machine. + +### Multi-unit + +Each Pi should have a unique hostname: + +```bash +python3 tools/xdj-pi-dev.py --set-hostname xdj-unit2 +``` + +Then from Claude Code: +- `discover_units` — lists all reachable XDJ units on the network +- `select_unit` — switches the active connection to a specific unit + +--- + +## Claude Code MCP setup + +Add to `.mcp.json` in your project root: + +```json +{ + "mcpServers": { + "xdj-pi-dev": { + "command": "python3", + "args": ["tools/xdj-pi-dev.py"] + } + } +} +``` + +Add to `.claude/settings.local.json`: + +```json +{ + "enabledMcpjsonServers": ["xdj-pi-dev"] +} +``` + +Restart Claude Code. Once connected, you can say things like: + +- *"push the skin and take a screenshot"* +- *"change the play button color in style.qss, push and screenshot"* +- *"restart Mixxx and navigate to the beat loop panel"* +- *"flash the firmware"* +- *"find all XDJ units on the network"* + +--- + +## CLI reference + +### Setup + +```bash +--check # preflight: deps, SSH, Mixxx, audio, Pico +--discover # scan network for all Pi units +--setup-pi-dhcp # configure Pi as DHCP server on eth0 +--setup-ssh-keys # passwordless SSH (recommended) +--set-hostname NAME # rename Pi (e.g. xdj-unit2) +--backup-image # backup SD card to .tar archive +--restore-ssh # recovery guide if SSH is locked out +``` + +### Skin development + +```bash +--push # push all skin files to Pi +--push "*.qss" # push only matching files +--pull # pull skin files from Pi to repo +--screenshot # capture Pi display +--screenshot --panel ks # navigate to panel first (hc/bl/bj/ks/st) +--restart # restart Mixxx +--watch # watch, auto-push + screenshot on save +--watch --panel hc # watch with panel navigation +``` + +### MIDI + +```bash +--push-midi # push MIDI mapping to Pi +--pull-midi # pull MIDI mapping from Pi +--midi-mon # stream live MIDI messages (Ctrl-C to stop) +``` + +### Pico firmware + +```bash +--setup-pico-cli # install arduino-cli on Pi (one-time) +--pico-compile # compile firmware on Pi +--pico-bootloader # reset Pico to UF2 bootloader +--pico-flash FILE.uf2 # flash a local .uf2 to Pi +--analyze # live GPIO signal analyzer +``` + +### Other + +```bash +--cmd 'CMD' # run arbitrary SSH command on Pi +--host 192.168.1.42 # target a specific IP or hostname +--ui # open interactive TUI (requires textual) +--about # show authors and credits +``` + +--- + +## Skin development guide + +See [`SKIN_DEV.md`](SKIN_DEV.md) for Mixxx widget types, layout rules, ConfigKeys, QSS constraints, and color palette — everything Claude needs to build and modify skin files correctly. diff --git a/tools/SKIN_DEV.md b/tools/SKIN_DEV.md new file mode 100644 index 0000000..963a102 --- /dev/null +++ b/tools/SKIN_DEV.md @@ -0,0 +1,358 @@ +# XDJ-100SX Skin Development Guide + +Context for Claude Code (via MCP) and human contributors working on the Mixxx skin. + +--- + +## Overview + +The skin runs on a **Raspberry Pi** connected to a **480×272 touchscreen** (landscape). +Mixxx renders the skin as a single-deck player — no second deck, no samplers, no vinyl control. + +The skin files live in `mixxx/SKIN/XDJ100SX/`. Push changes with: + +```bash +python3 tools/xdj-pi-dev.py --push # push all files +python3 tools/xdj-pi-dev.py --push "*.qss" # push only QSS +python3 tools/xdj-pi-dev.py --screenshot # see the result +``` + +Or use `--watch` to auto-push and screenshot on every save. + +--- + +## File Structure + +| File | Purpose | +|------|---------| +| `skin.xml` | Root — loads style.qss, sets minimum size, defines launch image | +| `config.xml` | Top-level layout: Day/Night toggle + deck area | +| `deck.xml` | Main deck template — info row, waveform, transport, performance panels | +| `deckminimal.xml` | Minimal deck view (collapsed state) | +| `tab.xml` | Reusable tab button template | +| `topbar.xml` | Top bar — BPM, pitch, track info | +| `waveform.xml` / `waveforms.xml` | Waveform display widgets | +| `overview.xml` | Track overview / position bar | +| `hotcues.xml` | Hot cue performance panel | +| `beatloop.xml` | Beat loop performance panel | +| `beatjump.xml` | Beat jump performance panel | +| `keyshift.xml` | Key shift performance panel | +| `stems.xml` | Stems performance panel | +| `beffect.xml` / `ceffectl.xml` / `ceffectr.xml` | Effect panels | +| `effects.xml` | Effects rack | +| `library.xml` | Library browser panel | +| `style.qss` | All QSS styling | + +--- + +## Layout System + +### Size syntax + +```xml +WIDTH,HEIGHT +``` + +Suffixes: +- `f` — fixed (exact pixels, no stretch) +- `me` — minimum, expands +- `max` — maximum (won't grow beyond this) +- `min` — minimum (won't shrink below this) +- No suffix — exact fixed size + +Examples: +```xml +65f,40f +0me,65max +me,me +``` + +### SizePolicy + +```xml +me,me +f,f +``` + +### Layout + +```xml +vertical +horizontal +``` + +### WidgetStack + +Shows one child at a time based on a ConfigKey value. Used for the performance panel tabs (hotcues, beatloop, etc.): + +```xml + + + ... + ... + + +``` + +### Templates + +Reusable XML fragments with variables: + +```xml + + + + + +``` + +--- + +## Widget Types + +### PushButton + +```xml + + MyButton + 65f,40f + 2 + + 0 + OFF + + + + 1 + ON + + + [Channel1],play + + +``` + +### Label + +```xml + +``` + +### NumberLabel / NumberDisplay + +For numeric values (BPM, pitch, time): + +```xml + + BPM + 60f,25f + + [Channel1],bpm + + +``` + +### WaveformDisplay + +```xml + + Waveform + me,80f + 1 + #000 + + #ff4444 + +``` + +### Overview (track position bar) + +```xml + + TrackOverview + me,30f + 1 + #111 + #ff0000 + +``` + +### WidgetGroup (container) + +```xml + + MyGroup + horizontal + me,40f + + + + +``` + +--- + +## ConfigKeys + +Format: `[Group],control` + +### Deck controls (single deck — always Channel1) + +| ConfigKey | Description | +|-----------|-------------| +| `[Channel1],play` | Play/pause toggle | +| `[Channel1],cue_default` | Cue button | +| `[Channel1],bpm` | Current BPM | +| `[Channel1],rate` | Pitch/rate slider | +| `[Channel1],volume` | Channel volume | +| `[Channel1],quantize` | Quantize on/off | +| `[Channel1],keylock` | Key lock on/off | +| `[Channel1],sync_enabled` | Sync on/off | +| `[Channel1],loop_enabled` | Loop active | +| `[Channel1],beatloop_size` | Current loop size | +| `[Channel1],hotcue_X_activate` | Trigger hot cue X | +| `[Channel1],hotcue_X_clear` | Clear hot cue X | +| `[Channel1],title` | Track title (text) | +| `[Channel1],artist` | Track artist (text) | +| `[Channel1],track_loaded` | 1 if track is loaded | + +### Tab/panel switching (skin-internal) + +The performance panels are driven by `[Channel2]` filter kill controls repurposed as tab flags — this is a hack to use existing bool ConfigKeys for panel visibility without needing Mixxx scripting: + +```xml + + + [Channel2],filterLowKill + visible + +``` + +**Do not change this pattern** — it would require updating both skin XML and the MIDI mapping script. + +### Skin-internal toggles + +```xml +[Skin],daynight_toggle +``` + +--- + +## QSS Styling + +Standard Qt stylesheet — subset of CSS. Applied via `style.qss`. + +### What works + +- `background-color`, `color`, `border`, `border-radius` +- `font-family`, `font-size`, `font-weight` +- `padding`, `margin` +- `min-width`, `max-width`, `min-height`, `max-height` +- `image: url(skin:/images/file.png)` — skin-relative paths +- State selectors: `WPushButton[value="1"]` — styling when button is active + +### What does NOT work + +- CSS Grid, Flexbox — not Qt +- CSS variables (`--my-var`) — not supported +- Animations / transitions +- `::before` / `::after` pseudo-elements +- `url()` with absolute paths — always use `skin:/` prefix for images +- `rgba()` with 4 args sometimes fails — test on device + +### Object name targeting + +```css +#MyButton { background: #333; } /* by ObjectName */ +WPushButton { border: 1px solid white; } /* by widget type */ +WPushButton[value="1"] { color: red; } /* active state */ +``` + +### Color palette (Pioneer style) + +``` +Play green: #6ee128 +Cue orange: #eb870f +Slip red: #d73535 +Tab yellow: #c3d541 +Header dark: #32323c +Title blue bg: #112f5c +Blue accent: #2d85cd +Text white: #e5e6ea +Background: #000000 +``` + +--- + +## Constraints & Rules + +### Screen + +- **Physical display**: 480×272px +- **Skin minimum**: 480×420 (Mixxx scales to fit, Pi display is rotated/scaled) +- Keep UI elements large enough to be finger-tappable (minimum ~40px touch targets) +- No horizontal scrolling — everything must fit in 480px width + +### Single deck only + +- Always use `[Channel1]` — never `[Channel2]`, `[Channel3]`, `[Channel4]` for actual controls +- `[Channel2]` filter kills are repurposed as panel tab visibility flags — don't use them for audio + +### Performance panels + +The skin has 5 performance panels (tabs): Hot Cue, Beat Loop, Beat Jump, Key Shift, Stems. +They are mutually exclusive (WidgetStack). Do not add a 6th tab without updating: +- The tab button row in `deck.xml` +- The WidgetStack in `deck.xml` +- The MIDI mapping in `XDJ100SX.midi.xml` and `XDJ100SX.js` + +### Images + +- Place in `mixxx/SKIN/XDJ100SX/images/` +- Reference as `skin:/images/filename.png` +- Keep image sizes minimal — Pi SD card and RAM are limited +- PNG preferred; avoid large JPEGs + +### Templates + +- Template files must start with `