README.md

August 28, 2026 · View on GitHub

A ddcutil varlink service for control of DDC Monitors/VDUs

Warning

When using this service, avoid excessively writing VCP values because each VDU's NVRAM likely has a write-cycle limit/lifespan. The suggested guideline is to limit updates to rates comparable to those observed when using the VDU's onboard controls. Avoid coding that might rapidly or infinitely loop, including when recovering from errors and bugs.

Non-standard manufacturer specific features should only be experimented with caution, some may have irreversible consequences, including bricking the hardware.

Important

This software is still in development and somewhat experimental.

The varlink interface design may change.

Tip

All methods in varlink/com.ddcutil.service.varlink have now been implemented.

The vdu_controls, a control panel for displays, can be configured to use ddcutil-varlink.

The aim of this service is to make it easier to create highly-responsive widgets and apps for ddcutil. The service is based on ddcutil-service, a similar D-Bus service.

The service is written in Rust. Compared to other implementations of similar services, the code for ddcutil-varlink is quite compact and the abstractions are relatively shallow. Providing you know Rust and a little about varlink, the code should be quite easy to follow.

Once built, running the executable should make a ddcutil varlink service available on unix:$XDG_RUNTIME_DIR/ddcutil-varlink.socket. The service runs under a user account (assuming libddcutil is installed with required permissions). Any type of varlink client can be used to interact with the service. For example, from the command line you could use the systemd varlinkctl command:

SERVICE="unix:$XDG_RUNTIME_DIR/ddcutil-varlink.socket"
INTERFACE="com.ddcutil.DdcutilInterface"
varlinkctl list-methods $SERVICE
varlinkctl introspect $SERVICE
varlinkctl call $SERVICE "${INTERFACE}.Detect" '{"include_offline":false}'
varlinkctl call $SERVICE "${INTERFACE}.GetVcp" '{"display_number":1,"vcp_code":16}'
varlinkctl call $SERVICE "${INTERFACE}.SetVcp" '{"display_number":5,"vcp_code":16,"new_value":50}'
varlinkctl call $SERVICE "${INTERFACE}.SetVcp" '{"display_number":2,"vcp_code":16,"new_value":70,"options":{"no_verify":true}}'
varlinkctl call $SERVICE "${INTERFACE}.GetMultipleVcp" '{"edid_base64":"AP///////wAi8Gk","vcp_codes":[16,20],"options":{"allow_edid_prefix":true}}'
varlinkctl --more --timeout=infinity call $SERVICE "${INTERFACE}.Subscribe" '{}'

Build and run

# Build and run a release version
cargo build --release
RUST_LOG=debug ./target/release/ddcutil-varlink

# Build and run for debugging
cargo build --debug
RUST_BACKTRACE=1 RUST_LOG=debug ./target/debug/ddcutil-varlink

Create the following service files and amend the ExecStart location.

# systemd/user/ddcutil.service                                                                                                                      ✔  10664  09:32:53
[Unit]
Description=ddcutil Varlink Service
Requires=ddcutil.socket
After=ddcutil.socket

[Service]
Type=simple
ExecStart=/usr/bin/ddcutil-varlink
Environment=RUST_LOG=info

[Install]
WantedBy=default.target
# systemd/user/ddcutil.socket
[Unit]
Description=ddcutil Varlink Service Socket

[Socket]
ListenStream=%t/ddcutil-varlink.socket
SocketMode=0600

[Install]
WantedBy=sockets.target

Install the service for a single user:

# Reload the user systemd manager daemon
systemctl --user daemon-reload

# Enable and start the socket unit immediately
systemctl --user enable --now ddcutil.socket

# Verify running
systemctl --user status ddcutil.socket

Installation via prebuilt binaries

Choice of implementations

For working from a .varlink file. I evaluated Rust libraries varlink and zlink. I found varlink to generate code that worked out of the box, so I've stuck with it. Trying to work with zlink generated code seemed to result in some difficult to resolve build errors. I may further experiment with zlink at some point.

Acknowledgements

Thanks go out to Sanford Rockowitz (rockowitz) for libddcutil, ddcutil.