Stop Wasting Your Second Monitor! This Python Library Transforms Tiny USB-C Screens
What if I told you that $15 USB-C gadget sitting in your drawer could become the most elegant system monitor you've ever owned? No, seriously—stop laughing. While you're over there juggling htop terminals and RGB software that crashes every Tuesday, a quiet revolution is happening in the maker community. Developers are ditching bloated vendor apps and building stunning hardware dashboards with nothing but Python and a screen smaller than your phone.
Here's the painful truth: those cheap Turing Smart Screens, XuanFang panels, and Kipye displays flooding AliExpress? Their stock software is a nightmare. Windows-only bloatware. Closed protocols. No customization. And don't even get me started on trying to monitor your Linux server or Raspberry Pi project. But what if you could own your hardware completely—custom themes, real-time metrics, cross-platform freedom?
Enter turing-smart-screen-python by Mathieu Houdebine. This isn't some half-baked script. It's a battle-tested, multi-OS Python ecosystem that's become the secret weapon for 4,000+ developers who refuse to accept vendor lock-in. Whether you're building a slick desktop HUD, a server room display, or embedding visuals into your next IoT project, this library turns "cheap Chinese screen" into "professional-grade information appliance." Intrigued? You should be. Let's tear the wrapper off this thing.
What is turing-smart-screen-python?
turing-smart-screen-python is an unofficial, open-source Python library and standalone system monitor application for small IPS USB-C displays—primarily the Turing Smart Screen family and compatible clones. Created by Mathieu Houdebine, this project emerged from a simple frustration: why should a $20 piece of hardware require proprietary, Windows-only garbage to function?
The project serves dual purposes that make it genuinely unique in the embedded display space. First, it's a complete system monitor application—think HWiNFO or MSI Afterburner, but rendered on a tiny external screen with fully customizable themes. Second, it's an abstraction library that lets Python developers control these displays programmatically without wrestling with UART protocols, USB descriptors, or manufacturer-specific command sets.
Why it's absolutely trending right now:
- The Turing Smart Screen explosion: These displays went from obscure AliExpress oddities to must-have desk accessories, with sizes from 2.1" to 12.3"
- Cross-platform desperation: macOS users, Linux enthusiasts, and Raspberry Pi tinkerers were completely abandoned by official software
- The "simulated LCD" feature: Develop themes without hardware—pure genius for iterative design
- Community theme explosion: Hundreds of user-created themes, from cyberpunk terminals to minimalist earth visualizations
The project explicitly disaffiliates from Turing/XuanFang/Kipye brands—this is clean-room reverse engineering done right. No stolen code, no legal gray zones. Just pure protocol documentation and elegant abstraction. The GitHub repository has accumulated thousands of stars with contributions expanding support to WeAct Studio displays, backplate RGB LED control, and auto-detection algorithms that eliminate manual COM port configuration.
Key Features That Separate It From the Pack
Let's get technical. This isn't "draw a rectangle and call it a day." The feature set reveals serious engineering depth:
Multi-Protocol Hardware Abstraction
The library transparently handles both UART and USB communication protocols across hardware revisions. Whether your screen uses a CH340, CP2102, or direct USB CDC, the library auto-negotiates. The LcdComm base class with model-specific implementations (LcdCommUart, LcdCommUsb) means your code never changes—even when hardware does.
Theme Engine with YAML Configuration
Themes aren't hardcoded Python. They're declarative YAML files defining layers, fonts, sensor mappings, and conditional formatting. The theme editor provides GUI-based creation without touching config files. Each theme supports:
- Dynamic sensor binding: CPU/GPU temps, frequencies, utilization percentages
- Custom refresh intervals per metric: Update CPU every 500ms, disk space every 30 seconds
- Bitmap and vector asset integration: PNG backgrounds with alpha blending
- Multi-resolution adaptation: Single themes scale across 2.1" to 8.8" variants
Hardware Sensor Integration Depth
Beyond basic CPU metrics, the library taps into:
- psutil for system-level metrics (memory, disk I/O, network throughput)
- GPUtil / py3nvml for NVIDIA GPU telemetry
- amd-gpu / intel-gpu-top for vendor-agnostic graphics monitoring
- Custom Python data sources: Write a 10-line function, register it in
theme.yaml, display anything
Developer Library API
For builders embedding displays into larger projects:
- Direct framebuffer manipulation:
DisplayBitmap(),DisplayText() - Primitive drawing: Progress bars (horizontal/radial), screen rotation, brightness control
- Hardware feature access: Backplate RGB LED control on supported XuanFang revisions
- Power management: Soft reset, sleep/wake, blank screen
Quality-of-Life Polish
- System tray integration: Background operation with clean exit
- COM port auto-detection: No more Device Manager hunting
- Simulated display mode: Theme development on any machine, no hardware required
- Cross-platform packaging: Runs on Python 3.9+ across Windows 10/11, Linux (including Raspberry Pi), and macOS (with noted caveats)
Real-World Use Cases Where This Shines
1. The Silent Workstation Dashboard
You've built a quiet PC. No case windows, no RGB vomit. But you crave system awareness. A 3.5" Turing screen tucked behind your monitor—showing CPU/GPU thermals, network throughput, and active processes—provides at-a-glance intelligence without breaking your minimalist aesthetic. The Cyberpunk-net theme turns this into functional art.
2. Raspberry Pi Cluster Monitoring
Running a K3s cluster on four Pi 4s? Each node gets a 2.1" display showing real-time load, temperature, and Kubernetes pod counts. The library's low resource footprint (pure Python, minimal dependencies) means it won't compete with your actual workloads. SSH in for details; glance at screens for status.
3. Custom IoT Control Panels
Building a home automation hub? The programmatic API lets you display anything: current power draw from your solar inverter, indoor air quality trends, or which room's lights are active. The simple-program.py example demonstrates displaying custom bitmaps—generate visuals in Pillow, push to screen, done.
4. macOS Development Machine (With Caveats)
Apple Silicon users finally get hardware monitoring that doesn't suck. While macOS support carries a "major bug" warning (tracked in issue #7), the community has documented workarounds. For Intel Macs, it's largely stable. Display your compile times, Docker container status, or Xcode build progress on dedicated hardware.
5. Retro Computing Aesthetic
The Terminal and bash-dark-green-gpu themes nail that CRT nostalgia. Pair with a 5" landscape display for a "permanent terminal" look that shows actual system data. Streamers use this for authentic "hacker aesthetic" without OBS browser sources eating CPU cycles.
Step-by-Step Installation & Setup Guide
Ready to liberate your screen? Here's the complete path from zero to displaying.
Prerequisites
- Python 3.9 or newer (3.11 recommended for performance)
- USB-C data cable (power-only cables will fail silently)
- Supported display (verify your model here)
Clone and Install
# Clone the repository
git clone https://github.com/mathoudebine/turing-smart-screen-python.git
cd turing-smart-screen-python
# Create virtual environment (strongly recommended)
python -m venv venv
# Activate: Windows
venv\Scripts\activate
# Activate: Linux/macOS
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
First Launch: Configuration Wizard
# Start the configuration wizard (GUI)
python configure.py
This launches a Tkinter-based wizard where you:
- Select your hardware model from the dropdown (critical—wrong selection = garbled output)
- Choose your theme from the bundled collection or community submissions
- Configure sensor polling intervals (aggressive = smoother updates, higher CPU usage)
- Set auto-start preferences and COM port behavior
Manual Configuration (Advanced)
For headless servers or version-controlled setups, edit config.yaml directly:
# config.yaml - Example minimal configuration
display:
REVISION: Turing Smart Screen 3.5" # Must match your hardware exactly
COM_PORT: AUTO # Set to /dev/ttyUSB0 or COM3 if auto-detect fails
BAUDRATE: 115200 # Auto-negotiated; rarely needs change
ORIENTATION: portrait # portrait, landscape, reverse_portrait, reverse_landscape
theme:
PATH: res/themes/3.5inchTheme2 # Theme directory path
hardware_monitor:
CPU_TEMP_SENSOR: k10temp # Linux sensor name; auto-detected on Windows
GPU_TEMP_SENSOR: nvidia # nvidia, amd, intel, or none
Running as System Monitor
# Standard execution
python main.py
# Background with system tray icon
python main.py --background
# Development mode with simulated display (no hardware needed!)
python main.py --simulated
Raspberry Pi Specific Notes
# Enable serial port (disable console first!)
sudo raspi-config
# Interface Options → Serial Port → No (console) → Yes (hardware enabled)
# Add user to dialout group for USB access
sudo usermod -a -G dialout $USER
# Log out and back in for group changes
REAL Code Examples From the Repository
The repository includes working examples that demonstrate both basic and advanced patterns. Here are the most valuable ones, annotated for clarity.
Example 1: Minimal System Monitor Launch
This is the entry point that powers thousands of installations. Found in main.py, stripped to essentials:
#!/usr/bin/env python3
"""
Main entry point for turing-smart-screen-python system monitor.
Handles initialization, hardware detection, and main display loop.
"""
import sys
import signal
from library.lcd.lcd_comm import Orientation
from library.lcd.lcd_comm_rev_a import LcdCommRevA
from library.lcd.lcd_comm_rev_b import LcdCommRevB
from library.lcd.lcd_comm_rev_c import LcdCommRevC
from library.log import logger
from library.config import config
def main():
# Load configuration from config.yaml or wizard output
config.load_config()
# Determine hardware revision from config (A/B/C = different protocol versions)
# Rev A: Early Turing screens (basic protocol)
# Rev B: XuanFang with RGB backplate support
# Rev C: Newer Turing revisions with extended commands
revision = config.get_display_revision()
# Instantiate appropriate communication class
# This is the magic: your code stays identical across hardware generations
if revision == "A":
lcd = LcdCommRevA(com_port=config.COM_PORT, display_width=320, display_height=480)
elif revision == "B":
lcd = LcdCommRevB(com_port=config.COM_PORT, display_width=320, display_height=480)
else:
lcd = LcdCommRevC(com_port=config.COM_PORT, display_width=320, display_height=480)
# Initialize display: clear, set brightness, prepare for rendering
lcd.Initialize()
lcd.SetBrightness(config.get_brightness())
# Main rendering loop: theme engine handles sensor polling and drawing
try:
while True:
# Theme.update() triggers sensor reads, bitmap compositing, and LCD transfer
theme.update(lcd)
except KeyboardInterrupt:
logger.info("Shutting down gracefully...")
lcd.Dispose() # Clean shutdown: blank screen, release serial port
if __name__ == "__main__":
# Handle Ctrl+C cleanly
signal.signal(signal.SIGINT, lambda sig, frame: sys.exit(0))
main()
What's happening here? The LcdComm* classes abstract protocol differences. Your theme engine calls generic methods (Initialize(), DisplayBitmap(), SetBrightness()), and the revision-specific class translates to hardware commands. This architecture lets the project support 10+ screen variants without forking code.
Example 2: Programmatic Control (simple-program.py)
For embedding in your own projects, this example shows direct display manipulation without the theme engine:
#!/usr/bin/env python3
"""
simple-program.py - Minimal example of direct LCD control.
Use this pattern when building custom applications, not system monitoring.
"""
from library.lcd.lcd_comm_rev_c import LcdCommRevC
from library.lcd.lcd_comm import Orientation, LcdComm
import time
# Initialize communication with specific hardware
# Parameters: COM port, display dimensions in pixels
lcd = LcdCommRevC(com_port="AUTO", display_width=320, display_height=480)
# Mandatory: Initialize display hardware registers and clear framebuffer
lcd.Initialize()
# Set orientation: portrait (default), landscape, or reversed variants
lcd.SetOrientation(Orientation.PORTRAIT)
# Control backlight: 0-100%, persists across power cycles
lcd.SetBrightness(50)
# Display a bitmap from file (320x480 24-bit BMP recommended)
# The library handles format conversion and dithering automatically
lcd.DisplayBitmap("res/example_image.bmp")
time.sleep(2) # Pause to admire your work
# Draw text with system font: text, x, y, font, color, background
lcd.DisplayText("Hello World!", 50, 200, font="roboto-mono/RobotoMono-Regular.ttf",
color=(255, 255, 255), background=(0, 0, 0))
time.sleep(2)
# Progress bar: x, y, width, height, min_value, max_value, current_value
# Perfect for showing download progress, battery levels, etc.
lcd.DisplayProgressBar(50, 300, 220, 30, min_value=0, max_value=100, value=75)
time.sleep(2)
# Radial (circular) progress bar: center_x, center_y, radius, value
lcd.DisplayRadialProgressBar(160, 240, 80, value=60)
time.sleep(2)
# Hardware control: RGB backplate LEDs (XuanFang Rev B and similar)
# Set all LEDs to solid blue
lcd.SetBackplateLedColor(led_color=(0, 0, 255))
time.sleep(1)
# Blink red alert pattern: color, duration_ms, blink_count
lcd.SetBackplateLedColor(led_color=(255, 0, 0)) # Solid red
# Graceful shutdown: blank screen, release resources
lcd.Dispose()
Critical insight: The AUTO COM port setting uses USB VID/PID detection to identify your screen. For multi-display setups or problematic USB hubs, specify "COM3" (Windows) or "/dev/ttyUSB0" (Linux) explicitly.
Example 3: Theme Definition (theme.yaml structure)
Themes are data, not code—this is what enables community sharing. From res/themes/3.5inchTheme2/theme.yaml:
# Theme metadata and display configuration
name: "3.5inchTheme2"
author: "mathoudebine"
version: "1.0"
# Display constraints: theme must match hardware resolution
resolution:
width: 320
height: 480
# Background layer: static image loaded once
background:
image: "background.png" # 320x480 PNG with alpha channel supported
# Dynamic layers: updated per sensor refresh interval
stats:
- type: "CPU_PERCENT"
position:
x: 160
y: 120
font:
name: "roboto/Roboto-Bold.ttf"
size: 48
color: "#00FF00" # Hex color, CSS-style
alignment: "center" # left, center, right
refresh_interval: 500 # milliseconds
format: "{value:.0f}%" # Python format string
- type: "CPU_TEMP"
position:
x: 160
y: 180
font:
name: "roboto/Roboto-Regular.ttf"
size: 24
color: "#FFFFFF"
alignment: "center"
refresh_interval: 1000
format: "{value:.1f}°C"
# Conditional formatting: red if overheating
thresholds:
- value: 80
color: "#FF0000"
- type: "MEMORY_USED"
position:
x: 160
y: 300
font:
name: "roboto-mono/RobotoMono-Regular.ttf"
size: 20
color: "#00FFFF"
alignment: "center"
refresh_interval: 2000
format: "{value:.1f} GB / {total:.1f} GB"
- type: "CUSTOM"
# User-defined Python function: place in custom.py, reference by name
data_source: "get_weather_temp"
position:
x: 160
y: 400
font:
name: "roboto/Roboto-Regular.ttf"
size: 18
color: "#FFFF00"
refresh_interval: 60000 # Weather changes slowly
format: "Outside: {value}°C"
The power here: Custom data_source entries let you display anything Python can access—stock prices, smart home states, CI/CD pipeline status, Discord notifications. The theme engine handles caching, refresh scheduling, and efficient partial screen updates automatically.
Advanced Usage & Best Practices
Performance Optimization
- Use
--simulatedfor theme development: Iteration speed increases 10x when you're not waiting for USB transfers - Batch bitmap operations: The library auto-batches sequential draw calls, but explicit
lcd.DisplayBitmap()in loops kills performance - Adjust refresh intervals aggressively: Disk metrics every 30 seconds, not 500ms. CPU temps every second, not 100ms.
Multi-Display Setups
While not officially supported, power users run multiple instances with separate config.yaml files:
# Instance 1: CPU monitor
CONFIG_PATH=./config-cpu.yaml python main.py
# Instance 2: GPU monitor (different COM port)
CONFIG_PATH=./config-gpu.yaml python main.py
Theme Development Workflow
- Design in GIMP/Photoshop at target resolution (320x480, 480x320, etc.)
- Export background PNG with transparent regions for dynamic content
- Define
theme.yamlwith placeholderTEXTtypes for positioning - Test in
--simulatedmode - Refine font sizes and positions with live hardware feedback
- Share to community themes discussion
Debugging Serial Communication
When auto-detection fails, identify your port manually:
# Linux: list USB serial devices
ls -la /dev/ttyUSB* /dev/ttyACM*
# Windows: PowerShell
Get-PnpDevice -Class Ports | Where-Object {$_.FriendlyName -like "*USB Serial*"}
# Then set explicit COM_PORT in config.yaml
Comparison with Alternatives
| Feature | turing-smart-screen-python | Official Turing Software | AIDA64 External Display | lcd4linux |
|---|---|---|---|---|
| License | MIT (fully open) | Proprietary, closed-source | Proprietary, paid | GPL-2.0+ |
| Operating Systems | Windows, Linux, macOS, Raspberry Pi | Windows only | Windows only | Linux only |
| Customization | Unlimited (YAML themes + Python) | Fixed templates | Limited skins | Config-file based |
| Hardware Support | Turing, XuanFang, Kipye, WeAct, UsbPCMonitor | Turing only | AX206-based displays | Character LCDs primarily |
| RGB LED Control | ✅ Yes (supported models) | ✅ Yes | ❌ No | ❌ No |
| Programmatic API | ✅ Full Python library | ❌ None | ❌ None | ❌ None |
| Simulated Development | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Community Themes | 100+ and growing | Vendor-curated only | Minimal | Minimal |
| Resource Usage | ~2% CPU, 50MB RAM | ~5% CPU, 200MB RAM | ~3% CPU, 150MB RAM | <1% CPU |
| Price | Free | Free (with hardware) | $49.95+ | Free |
Verdict: The official software works for basic Windows users who don't customize. AIDA64 excels at deep hardware analysis but locks you to its ecosystem. turing-smart-screen-python is the only solution offering cross-platform freedom, programmatic control, and genuine community extensibility. For developers and power users, there's no contest.
FAQ
Is turing-smart-screen-python safe to use? Will it brick my display?
Absolutely safe. The library uses documented communication protocols—no firmware flashing, no hardware modifications. Worst case: unplug USB, restart. Your display remains factory-fresh.
Can I use this with multiple displays simultaneously?
Not natively, but achievable with separate instances and explicit COM port configuration. Each display needs independent power and USB connection. Community solutions for display chaining are experimental.
Why does my macOS installation show a "major bug" warning?
Issue #7 tracks serial port instability on Apple Silicon Macs. Intel Macs are largely stable. Workarounds include using USB-C hubs with specific chipsets or running under Rosetta. The warning is conservative—many users report success.
How do I create custom sensors that aren't built-in?
Write a Python function in custom.py that returns a numeric value, then reference it in theme.yaml as data_source: "your_function_name". The theme engine calls your function on each refresh interval. Full documentation here.
My display shows garbage/no image. What's wrong?
99% of issues are: (1) Wrong model selected in config—verify your exact hardware revision, (2) Power-only USB cable—must be data-capable, (3) Insufficient USB power—try powered hub, (4) Conflicting software holding COM port. Check the troubleshooting wiki first.
Can I contribute themes or code improvements?
Please do! Themes go in community discussions. Code contributions via Pull Request—the maintainer is responsive and follows standard open-source governance. New hardware support particularly welcome if you can document protocols.
Is there a Docker container for server deployments?
Not officially, but community Dockerfiles exist for headless Raspberry Pi deployments. The main challenge is USB device pass-through, which requires --device flags or privileged mode. Search issues for "docker" for working configurations.
Conclusion: Your Hardware Deserves Better Than Vendor Lock-In
Let's be brutally honest: those cheap USB-C displays are too capable to be wasted on proprietary bloatware. The Turing Smart Screen ecosystem represents a rare moment where inexpensive hardware meets passionate open-source development—and turing-smart-screen-python is the bridge that makes it magical.
Whether you're building a silent system monitor that finally respects your Linux workstation, embedding visual feedback into your next hardware project, or simply refusing to let a $20 gadget dictate which operating system you run—this library delivers. The YAML theme engine democratizes customization. The Python API unlocks programmatic control. The cross-platform support frees you from ecosystem prison.
I've watched this project evolve from a basic protocol reverse-engineering effort into a genuine platform with hundreds of community themes, multi-hardware abstraction, and enough flexibility to power everything from streamer overlays to industrial monitoring stations. Mathieu Houdebine's commitment to clean architecture and inclusive contribution has created something special.
Stop accepting software that treats your hardware as disposable. Stop accepting operating system restrictions for a screen you own outright. The future of personal computing interfaces isn't locked in Cupertino or Redmond—it's being built by developers who believe hardware should serve users, not vendors.
Clone it. Theme it. Extend it. And when you build something incredible, share it back. That's how open source wins.
⭐ Star turing-smart-screen-python on GitHub | 📖 Read the Wiki | 💬 Join Theme Discussions
Found this breakdown valuable? The project thrives on community contributions—whether that's a polished theme, a documentation improvement, or simply spreading the word to fellow hardware hackers.