FastAPI service that drives multiple GPIO pins on Raspberry Pi to control relays for HTTP enabled / remote UGREEN USB-C switch control.
Compatible with: Raspberry Pi 3/4/5, Raspberry Pi Zero 2 W (and other models with 40-pin GPIO header)
This project automates the manual switching button on UGREEN USB-C Switch devices, allowing programmatic control via HTTP API. By using a relay connected to the GPIO pins, you can trigger the switch button remotely without physical button presses.
Supported GPIO Pins (BCM numbering): 4, 5, 6, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27
These pins have no conflicts with common peripherals (I2C, SPI, UART) and are safe for general-purpose use.
Required Hardware:
- Raspberry Pi (5, Zero 2 W, or other models with 40-pin GPIO header)
- Relay module - 3.3V Relay Module (recommended)
- UGREEN USB-C Switch
Supported UGREEN Devices:
- UGREEN USB-C Switch 2 Port (2 PC) USB 3.2
- UGREEN USB-C Switch 2 Port (2 PC) USB 3.0
- Other UGREEN USB-C switches with similar button circuitry
How it works: The GPIO pin controls a relay that simulates a manual button press on the UGREEN switch, causing it to toggle between connected PCs/devices.
This project is designed to enable a complete software-based KVM (Keyboard, Video, Mouse) solution by combining monitor switching with USB peripheral switching:
Monitor Switching (SwitchMonitors)
- Uses DDC/CI commands to switch monitor input sources
- Programmatically controls which computer your monitors display
- No physical monitor button pressing required
USB Peripheral Switching (This Repository)
- Integrates with a Raspberry Pi Zero HTTP API to control a USB switch
- Switches keyboard, mouse, and other USB peripherals between computers
- Controlled via simple HTTP requests to the Pi Zero
Combined Workflow: When you want to switch between computers, a single command can:
- Switch all monitor inputs to the target computer (using this SwitchMonitors script in Repo listed above)
- Switch USB peripherals to the target computer (via Pi Zero API call using this project repository)
This creates a seamless, software-controlled KVM experience without expensive KVM hardware, perfect for multi-PC setups where you want to share monitors and peripherals between work and personal computers, or between desktop and laptop systems.
| Item | Product | Price (as of Feb 2026) | Link |
|---|---|---|---|
| 1 | Raspberry Pi Zero 2 WH Kit | ~$35 | Amazon |
| 2 | SanDisk 32GB Ultraยฎ microSDHC | ~$22 | Amazon |
| 3 | 1 Channel 3V/3.3V Relay Module (pack of 4) | ~$8 | Amazon |
| 4 | Amazon Basics USB-A to Mini USB 2.0 Cable | ~$7 | Amazon |
Estimated Total Cost: ~$72
If you find this project useful and it's helped you automate your USB-C switching, please consider supporting it! Your support helps maintain and improve this project.
Support this project:
Other ways to help:
- โญ Star this repository - It helps others discover the project
- ๐ Report issues - Help improve the project by reporting bugs
- ๐ง Contribute - Submit pull requests with improvements or new features
- ๐ข Share - Tell others who might find this useful
Every bit of support is appreciated and motivates continued development!
โ Relay Control Behavior:
This controller uses a relay module to isolate and switch the USB-C switch button circuit:
- When ON (activated): GPIO pin outputs HIGH (3.3V) โ Relay closes โ Simulates button press
- When OFF (deactivated): GPIO pin outputs LOW (0V) โ Relay opens โ No button press
Raspberry Pi to Relay Module:
- GPIO Pin (e.g., GPIO 17 BCM, physical pin 11) โ Relay module IN or S (signal pin)
- 3.3V (physical pin 1) โ Relay module VCC
- GND (physical pin 9) โ Relay module GND
Relay to UGREEN USB-C Switch:
- Connect the relay's COM (common) terminal to the USB switch button's D- line
- Connect the relay's NO (normally open) terminal to USB switch GND
- When the relay activates, it closes the circuit between D- and GND, simulating a button press
Raspberry Pi Relay Module USB-C Switch
โโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Pin 1 (3.3V)โโโโโโโโโโโโโโ VCC โ โ โ
โ Pin 9 (GND) โโโโโโโโโโโโโโ GND โ โ โ
โ Pin 11(GP17)โโโโโโโโโโโโโโ IN/S โ โ โ
โ โ โ โ โ โ
โ โ โ COM โโโโโโผโโโโโโโโโโโโโโโ D- โ
โ โ โ NO โโโโโโผโโโโโโโโโโโโโโโ GND โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
When GPIO 17 = HIGH (3.3V): Relay closes, connects D- to GND (button press)
When GPIO 17 = LOW (0V): Relay opens, D- disconnected (no button press)
Full Color Image (Example using Pin 17 for 3.3V instead of Pin 1):
Raspberry Pi Connections:
- Physical Pin 1 (3.3V) or Pin 17 (3.3V) โ Relay VCC
- Physical Pin 9 (GND) โ Relay GND
- Physical Pin 11 (GPIO 17 BCM) โ Relay IN/S (signal)
Note: You can use any of the allowed GPIO pins (4, 5, 6, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27) for the relay signal connection. Pin numbers listed are in BCM format for API endpoints.
Run the setup script to install everything automatically:
chmod +x setup.sh
./setup.sh- Install system GPIO library (required on Raspberry Pi 5):
sudo apt-get update
sudo apt-get install -y python3-lgpio- Create a venv that can see system packages (so it finds
lgpio):
python3 -m venv --system-site-packages .venv
source .venv/bin/activate- Install Python dependencies (FastAPI + Uvicorn):
pip install -r requirements.txtStart the API (listens on all interfaces for remote access):
uvicorn gpio_switch_fastapi:app --host 0.0.0.0 --port 8000Enable SSL (cert + key files) and API key auth (set env GPIO_API_KEY):
GPIO_API_KEY="your-secret-key" uvicorn gpio_switch_fastapi:app \
--host 0.0.0.0 --port 8000 \
--ssl-certfile /path/to/cert.pem --ssl-keyfile /path/to/key.pemRequirements: A registered domain that you own and API access to your DNS provider.
This project is set up to obtain free certificates using acme.sh with the DNS-01 challenge. DNS-01 is chosen because it:
- Does not require exposing ports 80/443 or port-forwarding (works behind NAT/CGNAT)
- Supports wildcards and works even if your Pi is not publicly reachable
- Requires a real domain and DNS API credentials to prove ownership
By contrast, HTTP-01 requires your domain to resolve to the Pi and inbound port 80 to be reachable during issuance, which is often impractical on home/CGNAT networks.
The setup script (setup.sh) can install acme.sh and optionally guide issuance. If you issue a cert via acme.sh, point uvicorn to the generated files:
--ssl-certfile /home/piwifi/Documents/certs/<domain>.crt--ssl-keyfile /home/piwifi/Documents/certs/<domain>.key
Requirements: None - works with IP addresses, local hostnames (e.g., gpio.local), or any identifier.
For testing or internal use, the setup script can generate self-signed certificates. These certificates:
- Work immediately without DNS or external validation
- No domain ownership required - can use IP addresses or local names
- Cause browser security warnings (untrusted certificate)
- Are valid for 50 years (no renewal needed)
Install as a system service to start automatically on reboot (edit gpio-switch.service to set your username and project path first, or use the setup.sh script):
- Copy the service file to systemd:
sudo cp gpio-switch.service /etc/systemd/system/- Reload systemd and enable the service:
sudo systemctl daemon-reload
sudo systemctl enable gpio-switch.service
sudo systemctl start gpio-switch.serviceTo supply an API key to systemd, create <project_dir>/.env.gpio (e.g., /home/your-user/Documents/.env.gpio) with:
GPIO_API_KEY=your-secret-key
- Check service status:
sudo systemctl status gpio-switch.serviceUseful commands:
- Stop service:
sudo systemctl stop gpio-switch.service - Restart service:
sudo systemctl restart gpio-switch.service - View logs:
sudo journalctl -u gpio-switch.service -f - Disable auto-start:
sudo systemctl disable gpio-switch.service
Replace PI_IP with your Pi's address and {pin} with the GPIO pin number (e.g., 17, 22, 24).
HTTP (no SSL):
# Get root info (shows allowed pins)
curl http://PI_IP:8000/
# Control specific pins
curl http://PI_IP:8000/pin/17/status
curl -X POST http://PI_IP:8000/pin/17/on
curl -X POST http://PI_IP:8000/pin/17/off
curl -X POST http://PI_IP:8000/pin/17/toggle
# Pulse pin (simulates button press) - default 500ms delay
curl -X POST http://PI_IP:8000/pin/17/pulse
# Pulse with custom delay (e.g., 1000ms = 1 second)
curl -X POST "http://PI_IP:8000/pin/17/pulse?delay_ms=1000"
# Control a different pin (e.g., pin 22)
curl http://PI_IP:8000/pin/22/status
curl -X POST http://PI_IP:8000/pin/22/onHTTPS with self-signed certificate (use -k to bypass SSL warnings):
curl -k https://PI_IP:8000/pin/17/status
curl -k -X POST https://PI_IP:8000/pin/17/on
curl -k -X POST https://PI_IP:8000/pin/17/off
curl -k -X POST https://PI_IP:8000/pin/17/toggle
curl -k -X POST https://PI_IP:8000/pin/17/pulse
curl -k -X POST "https://PI_IP:8000/pin/17/pulse?delay_ms=1000"With API key authentication (add -H "X-API-Key: your-secret-key"):
curl -k -H "X-API-Key: your-secret-key" https://PI_IP:8000/pin/17/status
curl -k -H "X-API-Key: your-secret-key" -X POST https://PI_IP:8000/pin/17/on
curl -k -H "X-API-Key: your-secret-key" -X POST https://PI_IP:8000/pin/17/off
curl -k -H "X-API-Key: your-secret-key" -X POST https://PI_IP:8000/pin/17/toggle
curl -k -H "X-API-Key: your-secret-key" -X POST https://PI_IP:8000/pin/17/pulse
curl -k -H "X-API-Key: your-secret-key" -X POST "https://PI_IP:8000/pin/17/pulse?delay_ms=1000"Notes:
- Port 8000 must be open/allowed by any firewall.
- No sudo needed for the server unless your user lacks GPIO permissions.
This service uses BCM numbering and supports the following GPIO pins:
4, 5, 6, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27
These pins are safe general-purpose I/O pins that avoid conflicts with I2C, SPI, and UART interfaces.
Common Ground (GND) pins on Raspberry Pi 40-pin header:
- Physical pins 6, 9, 14, 20, 25, 30, 34, 39
Use any GND pin when completing the circuit for your GPIO loads/relays.
- โ Relay-based GPIO control (27 available pins)
- โ Active-high relay logic (HIGH = relay on, LOW = relay off)
- โ Pin validation (only safe GPIO pins allowed)
- โ
REST endpoints:
/pin/{pin_number}/{action} - โ Actions: status, on, off, toggle, pulse
- โ Pulse mode: simulates button press with configurable delay (default 500ms)
- โ Independent control of multiple relays simultaneously
- โ Lazy pin initialization (pins set up on first use)
- โ Automatic startup/shutdown GPIO init and cleanup
- โ API key authentication support
- โ SSL/HTTPS support
Permission denied: Run the API with a user that has GPIO access (or use sudo).
GPIO already in use: Another program may be using the GPIO pin. Reboot or stop the conflicting process.
Invalid pin error: Ensure you're using one of the allowed pins: 4, 5, 6, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27.
Relay not activating:
- Check wiring: GPIO pin โ Relay IN/S, 3.3V โ Relay VCC, GND โ Relay GND
- Verify correct GPIO pin number (BCM numbering, not physical pin)
- Ensure
python3-lgpiois installed and the venv uses--system-site-packages - Test relay with a multimeter to confirm it's switching
- Check relay LED indicator (should light when activated)
USB-C switch not responding:
- Verify relay COM and NO terminals are connected to USB switch D- and GND
- Test the USB switch button manually to confirm it works
- Check that relay is actually closing when GPIO goes HIGH
GET /- List allowed pins and endpoint patternsGET /pin/{pin}/status- Get current state of a pinPOST /pin/{pin}/on- Activate relay (set GPIO HIGH - relay closes)POST /pin/{pin}/off- Deactivate relay (set GPIO LOW - relay opens)POST /pin/{pin}/toggle- Toggle relay statePOST /pin/{pin}/pulse?delay_ms=500- Pulse relay (onโdelayโoff) to simulate button press

