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
Installing the ddcutil-varlink as a systemd auto-started service
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
Optional ddcutil-varlink-client
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.