A tool to control EZCOO KVM switches via the serial interface
Project description
ezcoo-cli
A tool to control EZCOO KVM switches via the serial interface.
Tested Devices: EZCOO EZ-SW41HA-KVMU3L with firmware version 2.03 (should be equal to EZ-SW41HA-KVMU3P)
Installation
From PyPI
Install using uv:
uv add ezcoo-cli
From AUR (Arch Linux)
Install from the Arch User Repository:
yay -S ezcoo-cli
# or
paru -S ezcoo-cli
AUR package: https://aur.archlinux.org/packages/ezcoo-cli
From Source
git clone https://github.com/Luminger/ezcoo-cli
cd ezcoo-cli
uv sync
CLI Usage
The CLI provides commands to control your EZCOO KVM switch through a serial connection.
KVM Switching
Switch between inputs:
# Switch to input 2
ezcoo-cli input switch 2
# Switch to input 3 (output 1 is implicit)
ezcoo-cli input switch 3 --output 1
Check current status:
# View system information
ezcoo-cli status
# Check which input is currently active
ezcoo-cli output routing
# Check stream status
ezcoo-cli output stream
Get device information:
# View available commands
ezcoo-cli help
# Get raw device response (useful for debugging)
ezcoo-cli help --format raw
ezcoo-cli status --format raw
Output Formats
Most query commands support multiple output formats to suit different use cases. You can specify the format using the --format (or -f) flag:
pretty- Human-readable formatted output (default)json- Machine-readable JSON output for scripting and automationraw- Raw device response as received from the KVM
For example, to get system status as JSON:
ezcoo-cli status --format json
# or using the short form
ezcoo-cli status -f json
[!NOTE] Breaking Change in v0.2.0: Version 0.1.0 always printed raw output. Starting from v0.2.0, commands default to pretty-formatted output. Use
--format rawto get the previous behavior.
Device Connection and Addressing
By default, the tool connects to /dev/ttyUSB0 at address 0 (single device mode). You can specify a different device and address:
# Use a different serial device
ezcoo-cli -d /dev/ttyUSB1 input switch 2
# Communicate with device at address 5
ezcoo-cli --address 5 status
# Short form
ezcoo-cli -a 5 status
Multi-Device Setup
EZCOO devices support address-based multi-device setups where multiple KVM switches can share a single serial connection. Each device needs a unique address (0-99), with 0 being the default for single-device setups.
Discovering devices on the serial port:
# Scan all addresses (0-99)
ezcoo-cli system discover
# Scan specific range
ezcoo-cli system discover --start 0 --end 10
Changing device addresses:
# Change device at address 0 to address 5
ezcoo-cli system set-address 5
# Change device at address 5 to address 10
ezcoo-cli --address 5 system set-address 10
[!WARNING] After changing a device's address, you must use the
--addressoption to communicate with it at its new address.
Library Usage
You can use ezcoo-cli as a library in your Python projects. There are two interfaces available:
High-Level KVM Interface (Recommended)
The high-level interface provides type-safe, structured access to KVM functionality:
from pathlib import Path
from ezcoo_cli.kvm import KVM
# Create KVM instance (default address 0)
kvm = KVM(Path("/dev/ttyUSB0"))
# Get system information
status = kvm.get_system_status()
print(f"Firmware: {status.firmware_version}")
print(f"Address: {status.system_address}")
# Switch inputs
kvm.switch_input(2) # Switch to input 2
# Get current routing
routing = kvm.get_output_routing()
print(f"Output {routing.output} -> Input {routing.input}")
# Get stream status
stream = kvm.get_stream_status()
print(f"Stream enabled: {stream.enabled}")
# Get help information
help_info = kvm.get_help()
print(f"Available commands: {help_info.total_commands}")
# Working with devices at specific addresses
kvm_at_5 = KVM(Path("/dev/ttyUSB0"), address=5)
status = kvm_at_5.get_system_status()
# Change device address
kvm.set_device_address(5) # Change from 0 to 5
kvm.address = 5 # Update instance to use new address
# Access raw response for any command
print(status.raw_response) # Raw device output
print(status.command) # Command that was sent
Low-Level Device Interface
For direct command access, use the Device class:
from pathlib import Path
from ezcoo_cli.device import Device
# Basic usage
with Device(Path("/dev/ttyUSB0")) as device:
# Switch input 2 to output 1
device.write("EZS OUT1 VS IN2")
# Get help
device.write("EZH")
for line in device.readlines():
print(line, end="")
Development
This project uses uv for dependency management and ruff for linting.
# Install development dependencies
uv sync --dev
# Run linting
uv run ruff check
# Run formatting
uv run ruff format
Testing
The test suite uses pytest-reserial to record and replay serial device interactions, allowing tests to run without physical hardware.
Running Tests
Replay Mode (no hardware needed):
./scripts/test-replay.sh
# or: uv run pytest tests/ --replay -v
Hardware Mode (with real device):
./scripts/test-with-hardware.sh
# or: uv run pytest tests/ -v
Record Mode (capture new traffic):
./scripts/test-record.sh
# or: uv run pytest tests/ --record -v
Recorded Traffic
pytest-reserial automatically records serial traffic in the tests/ directory, with one recording file per test module.
Important: Commit these recording files to version control so others can run tests without hardware.
Prerequisites for Recording
- EZCOO device connected to
/dev/ttyUSB0 - User has permissions to access serial device:
sudo usermod -a -G dialout $USER # Log out and back in for changes to take effect
Command Support Status
Based on testing with EZCOO EZ-SW41HA-KVMU3L devices running firmware 2.03:
Working GET Commands
| Command | Description | Response |
|---|---|---|
EZSTA |
Get system status | System info with address, firmware, serial config |
EZH |
Get help | Complete command list |
EZG OUTx VS |
Get output routing | Current input routing |
EZG OUT1 STREAM |
Get stream status | Stream on/off status |
Working SET Commands
| Command | Description | Response | CLI Command |
|---|---|---|---|
EZS OUTx VS INy |
Switch input | No response (SET command) | ezcoo-cli input switch <input_num> |
EZS ADDR xx |
Set system address | No response (SET command) | ezcoo-cli system set-address <new_address> |
Unsupported/Unimplemented Commands
Query commands that don't return data (Firmware 2.03):
These commands have been tested and confirmed to return no data on firmware 2.03. They are not exposed by the project as they don't work on this firmware version.
| Command | Description | Test Result |
|---|---|---|
EZG INx SIG STA |
Get input signal status | No response from device |
EZG INx EDID |
Get EDID information | No response from device |
EZG ADDR |
Get system address | No response from device |
EZG AUTO MODE |
Get auto switch mode status | No response from device |
EZG CAS |
Get cascade mode status | No response from device |
EZG STA |
Get system status (alternative) | No response from device (use EZSTA instead) |
SET commands with unknown/unclear effect (not implemented in this tool):
These SET commands have been tested and the device accepts them without errors (no response, which is normal for SET commands). However, their actual effect is unclear - either no observable changes occurred or the expected behavior was not seen.
| Command | Description | Test Result | Reason Not Implemented |
|---|---|---|---|
EZS CAS EN/DIS |
Set cascade mode enable/disable | Accepted by device, no observable effect | Effect unclear |
EZS OUTx VIDEOy |
Set output video mode (BYPASS/4K->2K) | Accepted by device, no observable effect | Effect unclear |
EZS INx EDID y |
Set input EDID | Accepted by device, no observable effect | Effect unclear |
EZS RST |
Reset to factory defaults | Accepted by device, but address was NOT reset (still at 01 after reset) | Effect unclear - may not work or may only reset some settings |
License
This project is licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later).
See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ezcoo_cli-0.2.0.tar.gz.
File metadata
- Download URL: ezcoo_cli-0.2.0.tar.gz
- Upload date:
- Size: 1.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f756973d339f7a71e1cdc47704b3f0cd7cd17357b852474634df0eb76a25b95f
|
|
| MD5 |
32d5fa54e06bdaa30ecbc8fe0f71dc12
|
|
| BLAKE2b-256 |
608354e99dae1acaa080e5c81823979dd6e0b475fbf185e9a63eee6acf1e2975
|
File details
Details for the file ezcoo_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ezcoo_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7a811e515a1992f8265a71f2e69e995cc93824a16fa9c0ed92789ff7de022e8
|
|
| MD5 |
f6baebf36d041ab321af39abbeef0853
|
|
| BLAKE2b-256 |
90b91b27ab5111faef8d96fcb4f25d104e104269465823131bbfe3843cf5b576
|