Skip to content
miruasPublic

About

Arduino Mega 2560 based 10-key Stream Deck-style controller with a Windows desktop agent

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DeskDeck

DeskDeck is a compact 10-key Stream Deck-style controller built from an Arduino Mega 2560 and a Windows desktop configuration app.

The Arduino firmware only reports physical button state over USB Serial. The desktop app owns all higher-level behavior: serial connection, profiles, key assignment, action execution, logs, and tray/background operation.

Current Scope

Implemented:

  • 10 physical mechanical switches
  • Arduino Mega 2560 firmware
  • USB Serial protocol at 115200 baud
  • Windows desktop configuration app
  • 2 x 5 key layout in the GUI
  • One configurable action per key
  • Profiles
  • Logs
  • Auto-connect to the Arduino serial port
  • System tray/background mode
  • Windows logon auto-start through the current user's Run registry key
  • Two 16 x 2 I2C LCDs
  • Three LCD navigation buttons
  • One potentiometer on A0
  • Local Windows PC telemetry on the LCD menu

Hardware

The device uses 10 two-pin mechanical switches. One leg of every switch is connected to a shared GND rail. The other leg of each switch is connected directly to a digital pin on the Arduino Mega 2560.

No external pull-up or pull-down resistors are used. The firmware enables the Arduino internal pull-up resistors with INPUT_PULLUP.

Because of INPUT_PULLUP:

  • Released button reads HIGH
  • Pressed button reads LOW

Pin Map

Physical Key GUI Label Arduino ID Arduino Mega Pin
Key 1 1 1 D22
Key 2 2 2 D23
Key 3 3 3 D24
Key 4 4 4 D25
Key 5 5 5 D26
Key 6 6 6 D27
Key 7 7 7 D28
Key 8 8 8 D29
Key 9 9 9 D30
Key 10 0 10 D31

Key 10 is displayed as 0 in the desktop app, but its config key and Arduino ID remain 10.

Additional controls:

Control Arduino Mega Pin
SELECT D32
BACK D33
MODE D34
Potentiometer wiper A0

The navigation buttons are wired to GND and use INPUT_PULLUP, so pressed reads LOW.

The top LCD uses the Mega hardware I2C bus. The bottom LCD uses a separate software I2C bus so both LCD backpacks can keep the same 0x27 address.

Display I2C Address Arduino Mega Pins
Top LCD 0x27 SDA D20, SCL D21
Bottom LCD 0x27 SDA D53, SCL D52

Physical Layout

1 2 3 4 5
6 7 8 9 0

Serial Protocol

The Arduino opens Serial at 115200 baud and prints the startup banner:

STREAM_DECK_READY
BUTTON_COUNT=10

Macro button events are newline-delimited JSON:

{"type":"button","id":1,"action":"pressed"}
{"type":"button","id":1,"action":"released"}

The firmware does not send action names, file paths, URLs, commands, hotkeys, or macro data. The desktop app only accepts button ID and physical state from Arduino. Actions are loaded from the local JSON config file.

Control button events are also physical-state-only JSON:

{"type":"control","control":"select","action":"pressed"}
{"type":"control","control":"select","action":"released"}

Potentiometer page changes are emitted only when the filtered A0 value crosses a menu page boundary:

{"type":"menu","control":"pot","action":"page_changed","page":2,"raw":348,"normalized":0.340}

The desktop app sends LCD frames and notifications to Arduino:

{"type":"display_frame","top":{"line1":"CPU 42%    58C","line2":"RAM 9.2 / 32G"},"bottom":{"line1":"> CPU Details","line2":"Page 2/7  LIVE"}}

This release monitors only the Windows computer running DeskDeck. Homeserver integration is not included.

LCD Menu

The desktop app owns the menu state. Arduino only reports physical input and renders display commands.

Pages:

0 Overview
1 CPU
2 GPU
3 Memory
4 Disk
5 Network
6 System

Controls:

  • SELECT short press: toggles detail mode.
  • SELECT long press: toggles pinned mode.
  • BACK short press: returns to Overview.
  • BACK long press: resets menu state.
  • MODE short press: toggles auto rotate.
  • MODE long press: toggles LCD backlight.

Auto rotate advances every 5 seconds through Overview, CPU, GPU, Memory, Disk, Network, and System. Pinned mode blocks potentiometer page changes and auto rotate.

Startup LCD text before the first desktop frame:

Top:
DeskDeck v0.2
Waiting for PC

Bottom:
USB Serial Ready
Page: Overview

Action Model

Each key has one action. The action runs when the desktop app receives a physical pressed event from Arduino.

Mouse-clicking a keycap in the GUI only selects that key for editing. It does not run the assigned action.

Supported action types:

  • none
  • launch
  • url
  • hotkey
  • command

command actions are executed with subprocess.Popen([...], shell=False). Program and arguments are stored separately.

Project Tree

deskdeck/
|-- README.md
|-- platformio.ini
|-- src/
|   `-- main.cpp
|-- include/
|   `-- README
|-- lib/
|   `-- README
|-- test/
|   `-- README
`-- desktop-agent/
    |-- main.py
    |-- requirements.txt
    |-- README.md
    |-- config.example.json
    |-- pytest.ini
    |-- deskdeck/
    |   |-- application.py
    |   |-- main_window.py
    |   |-- constants.py
    |   |-- theme.py
    |   |-- models.py
    |   |-- config_manager.py
    |   |-- serial_worker.py
    |   |-- serial_controller.py
    |   |-- action_executor.py
    |   |-- button_controller.py
    |   |-- profile_manager.py
    |   |-- logger.py
    |   |-- pages/
    |   `-- widgets/
    `-- tests/

Firmware

The firmware lives in src/main.cpp and is built with PlatformIO.

Responsibilities:

  • Configure D22-D31 as INPUT_PULLUP
  • Read 10 buttons
  • Configure D32-D34 as INPUT_PULLUP navigation buttons
  • Read the A0 potentiometer
  • Drive topDisplay on hardware I2C at 0x27
  • Drive bottomDisplay on software I2C SDA D53 / SCL D52 at 0x27
  • Debounce every button independently
  • Use millis() for non-blocking timing
  • Print startup status
  • Print pressed/released JSON events
  • Receive local PC telemetry JSON and render the LCD menu

The firmware deliberately does not know about profiles or actions.

Build Firmware

pio run

Upload Firmware

pio run --target upload

Monitor Serial Output

pio device monitor --baud 115200

Close the serial monitor before connecting from the desktop app. A COM port can only be opened by one process at a time.

Desktop App

The desktop app lives in desktop-agent/.

Responsibilities:

  • Detect serial ports
  • Connect to the Arduino at 115200 baud
  • Parse startup lines and JSON button events
  • Collect local Windows CPU, memory, disk, and uptime telemetry
  • Send telemetry JSON to the Arduino LCD menu
  • Show live key press state
  • Store profiles in config.json
  • Run local actions for physical button presses
  • Show logs
  • Run in the Windows system tray
  • Auto-start at Windows logon

Install Desktop Dependencies

cd desktop-agent
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txt

Run Desktop App

python main.py

Run in Tray Mode

python main.py --tray

Run Tests

pytest

Windows Auto-Start

DeskDeck is configured to auto-start for the current Windows user by adding a value under:

HKCU\Software\Microsoft\Windows\CurrentVersion\Run

The command starts the GUI without opening the main window:

pythonw.exe main.py --tray

This is intentionally not a Windows Service. Windows Services run in session 0 and are not suitable for tray icons or interactive GUI windows.

Configuration

Default config path:

desktop-agent/config.json

config.json is generated on first run and ignored by Git because it contains local COM port selections and user-specific application paths. The repository includes desktop-agent/config.example.json as a clean template.

Example button config:

{
  "name": "Discord",
  "action": {
    "type": "launch",
    "path": "C:/Users/Administrator/AppData/Local/Discord/Update.exe",
    "args": ["--processStart", "Discord.exe"]
  }
}

The config file is saved atomically: DeskDeck writes a temporary file first, then replaces the real config file.

Troubleshooting

Arduino is connected but DeskDeck shows disconnected

  • Close Arduino Serial Monitor, PlatformIO monitor, or any program using the same COM port.
  • Open the Connection page and click Refresh Ports.
  • Confirm the selected COM port matches the Arduino in Device Manager.
  • Check the Logs page for the exact serial error.

A key does not run its action

  • Confirm the Arduino sends a pressed JSON line for that key.
  • Check that the selected profile has an action configured for that key.
  • Check Logs for action validation or launch errors.

Discord does not launch

Discord usually needs to be launched through Update.exe:

{
  "type": "launch",
  "path": "C:/Users/Administrator/AppData/Local/Discord/Update.exe",
  "args": ["--processStart", "Discord.exe"]
}

The app is running but no window is visible

DeskDeck may be hidden in the system tray. Click the DeskDeck tray icon or use the tray context menu and select Open DeskDeck.

About

Arduino Mega 2560 based 10-key Stream Deck-style controller with a Windows desktop agent

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages