A python-based G15 applet
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-18 21:10:46 +02:00
core initial commit 2026-09-18 15:39:36 +02:00
lcd initial commit 2026-09-18 15:39:36 +02:00
screens fix bug that would cause spotify to pause on view switch 2026-09-18 15:54:22 +02:00
services fix DialogCommunity on TG 2026-09-18 21:10:46 +02:00
.gitignore fix DialogCommunity on TG 2026-09-18 21:10:46 +02:00
main.py fix tumblr tokens not authenticating, add support for global steam notifications for games played, add support for telegram gdm replies pushes 2026-09-18 16:32:21 +02:00
pyproject.toml initial commit 2026-09-18 15:39:36 +02:00
README.md initial commit 2026-09-18 15:39:36 +02:00
setup_wizard.py fix tumblr tokens not authenticating, add support for global steam notifications for games played, add support for telegram gdm replies pushes 2026-09-18 16:32:21 +02:00
smoke_test.py initial commit 2026-09-18 15:39:36 +02:00

laura / girlcdfailure

A multi-screen dashboard for the Logitech G15:

Spotify now-playing, a clock, a system monitor, a Discord voice-activity screen and an aggregated notifications feed (Twitch going live, Signal / Discord / Steam / Telegram / Tumblr interactions / Mastodon).

Screens rotate automatically (can be disabled); the G15's 4 LCD soft buttons (G1-G4) control it:

Button Action
G1 Previous screen (on Alerts: page to older alerts; leaves at the oldest page)
G2 Next screen (on Alerts: page back to newer alerts; leaves at the newest page)
G3 Toggle auto-rotate on/off
G4 Screen-specific action (Spotify: play/pause; Alerts: mark read + jump to newest)

Install

  1. Install Python 3.10+ and Logitech Gaming Software (G HUB is not supported because it doesn't even support this Keyboard!).
  2. uv sync
  3. uv run main.py --setup and answer the questions (everything optional). It writes config.yaml for you.
  4. uv run main.py

First-run tip: if you enabled QR logins (Discord, Steam) plus other console logins (Telegram code, Steam Guard), do them one at a time -- temporarily disable the others. QR codes expire after ~2 minutes and the terminal gets confusing with several printed at once. After the first successful login each token/session is cached, so later starts are quiet.

Troubleshooting

  • "Could not load LogitechLcd.dll": search your machine for that filename (it's inside your LGS install folder, usually under ...\Logitech Gaming Software\SDK\LCD\x64 or \x86 -- pick the one matching your Python: 64-bit Python needs the x64 build), then set app.lgs_dll_path in config.yaml to the exact path you found. The older LogitechLcdEnginesWrapper.dll works too if you have it.
  • LogiLcdInit failed: make sure LGS is actually running, the G15 shows up in it, and no other LCD applet currently has focus.
  • Screen looks garbled/inverted: try flipping app.invert in config.yaml.
  • Fonts look huge/tiny/off: the app tries a few common Windows fonts (Consolas, Tahoma, Arial) at small point sizes and falls back to PIL's built-in bitmap font if none are found; exact layout may need a pixel or two of tweaking in screens/*.py depending on which font actually loads on your system.

Project layout

main.py                    entry point / main loop (--setup runs the wizard)
setup_wizard.py            first-time setup: writes config.yaml interactively
core/
  renderer.py               drawing helpers (fonts, marquee text, bars)
  screen_manager.py          screen rotation + button handling + popover overlay
  alerts.py                  shared notification feed
  popover.py                 top-right push popover (alerts + voice activity)
  qr_display.py              QR codes as terminal ASCII + PNG files
lcd/
  lgs_backend.py             real G15 hardware via Logitech's LCD SDK
  preview_backend.py         on-screen test window, no hardware needed
screens/                    one file per screen (rendering only)
services/
  discord_qr.py             Discord QR login (remote-auth gateway)
  steam_qr.py               Steam QR login (mobile approval + CM token logon)
  ...                       one file per integration (polling/background threads)

Add a new screen by creating a screens/your_screen.py (subclass screens.base.Screen) and adding it to the screens = [...] list in main.py.