How to Integrate OpenLogi with Other Systems: A Complete IPC and RPC Guide
Integrate OpenLogi with external systems by using the openlogi-ipc crate to establish a Tarpc client connection over local sockets, enabling direct RPC calls to the agent from Rust binaries, scripts, or external services.
OpenLogi organizes its codebase as a clean three-tier architecture where the GUI, agent, and shared IPC layer remain strictly separated. This design allows any external tool or service to communicate with running OpenLogi instances without embedding the full desktop application. By leveraging the IPC contract defined in crates/openlogi-ipc, developers can build headless automations, custom overlays, or bridge services that control Logitech devices programmatically.
Understanding OpenLogi's Three-Tier Architecture
The repository splits functionality into three distinct crates that communicate via local sockets. Understanding these boundaries is essential for stable integrations.
- IPC Contract (
crates/openlogi-ipc): Defines theAgentClienttrait and Tarpc service methods incrates/openlogi-ipc/src/ipc.rs. This crate handles the transport layer and protocol versioning. - Agent Core (
crates/openlogi-agent-core): Implements the server side of the IPC contract, managing device I/O, hook runtime, and DPI state. The agent exposes all functionality through the RPC surface. - User Interfaces (
crates/openlogi-cliandcrates/openlogi-desktop): Provide thin clients that invoke the same RPC methods available to your custom code.
Because the IPC layer is independent of any UI, you can run the agent headless and drive it entirely through the programmatic API.
Setting Up the IPC Client Connection
To begin integrating, add the IPC crate to your Cargo.toml and establish an asynchronous connection to the running agent.
Add the dependency referencing the local workspace:
openlogi-ipc = { path = "../openlogi/crates/openlogi-ipc" }
The connect() function in crates/openlogi-ipc/src/client.rs handles the local socket transport initialization and mandatory protocol handshake. Implement the connection as follows:
use openlogi_ipc::client::connect;
use tarpc::context;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Establish the IPC connection and retrieve the protocol version.
let conn = connect().await?;
println!("Connected to agent version {}", conn.version);
// Example: query the list of paired devices.
let devices = conn.client.list_devices(context::current()).await?;
for d in devices {
println!("{} – {} ({})", d.slot, d.codename, d.kind);
}
Ok(())
}
The connect() function returns a Connection { client, version } struct. Under the hood, it creates a local-socket stream via transport::connect(), wraps it for Tarpc, spawns the client, and performs the protocol_version handshake defined in crates/openlogi-ipc/src/client.rs at lines 47-58.
Calling RPC Methods
Once connected, you invoke any method defined in the AgentClient trait. The full API surface lives in crates/openlogi-ipc/src/ipc.rs and includes device enumeration, DPI adjustment, and lighting control.
Query available devices:
let devices = conn.client.list_devices(context::current()).await?;
Modify device settings programmatically:
// Change DPI on a specific device
conn.client.set_dpi(context::current(), device_id, 800, 1600).await?;
Other available methods include toggle_smartshift, set_lighting, and run_custom_action. The trait is re-exported through crates/openlogi-ipc/src/lib.rs at lines 13-18, ensuring your integration stays synchronized with the agent's capabilities.
Handling Protocol Versioning
OpenLogi uses a hardcoded PROTOCOL_VERSION constant to track RPC compatibility. The client connection exposes the agent's reported version through conn.version, but does not automatically validate compatibility.
Compare the connected version against your crate's constant:
if conn.version != openlogi_ipc::PROTOCOL_VERSION {
eprintln!("Version mismatch: agent {}, client {}",
conn.version, openlogi_ipc::PROTOCOL_VERSION);
// Handle upgrade logic here
}
This check prevents subtle bugs when the agent binary and your integration code drift out of sync across updates.
Common Integration Patterns
Scripted CLI Invocation
The openlogi binary in crates/openlogi-cli provides commands like list, assets, and diag. Shell scripts can invoke these directly for automation tasks that do not require custom logic:
openlogi diag dpi # Performs a read/write/read-back DPI cycle
Embedded RPC Client
Compile a custom Rust binary linking against openlogi-ipc to embed OpenLogi control directly into your application. This pattern works for game launchers, productivity tools, or system tray utilities that need fine-grained device manipulation without spawning external processes.
External Service Bridge
Wrap the IPC client in a REST or WebSocket endpoint to expose OpenLogi functionality to non-Rust systems. A minimal actix-web service can accept JSON payloads and forward them to set_lighting or set_dpi methods, enabling home automation hubs to trigger Logitech device actions.
Overlay Extensions
The crates/openlogi-overlay crate demonstrates an advanced integration pattern: it acts as an IPC client while rendering a GUI overlay. Fork this entry point (located at crates/openlogi-overlay/src/main.rs) to add custom macro playback or contextual actions while reusing the existing transport implementation.
Summary
- Add
openlogi-ipcto yourCargo.tomlto access the RPC client and transport layers. - Use
connect()to establish a local socket connection and retrieve the protocol version fromcrates/openlogi-ipc/src/client.rs. - Call methods like
list_devices,set_dpi, andset_lightingdefined incrates/openlogi-ipc/src/ipc.rsthrough the returned client. - Check
PROTOCOL_VERSIONagainstconn.versionto ensure compatibility between your integration and the running agent. - Run headless by communicating directly with the agent core without launching the GUI, enabling server-side automation and bridge services.
Frequently Asked Questions
Can I control OpenLogi devices without running the desktop GUI?
Yes. The agent process (crates/openlogi-agent) runs independently of the GUI. By connecting via the IPC client, you can send RPC commands to a headless agent instance, making OpenLogi suitable for servers or automation hosts that never load the desktop interface.
What RPC methods are available for device control?
The AgentClient trait in crates/openlogi-ipc/src/ipc.rs exposes methods including list_devices, set_dpi, toggle_smartshift, set_lighting, and run_custom_action. Consult this file for the complete API surface, as it represents the authoritative contract between clients and the agent.
How does the IPC transport work across operating systems?
The transport layer in crates/openlogi-ipc/src/transport.rs abstracts platform-specific local sockets (Unix domain sockets on Linux/macOS, named pipes on Windows). The connect() function handles these details automatically, providing a unified async interface regardless of the host OS.
What should I do if the protocol version changes?
Compare conn.version (returned by the connection) with the PROTOCOL_VERSION constant exported by the openlogi-ipc crate. If they differ, upgrade either the agent binary or your client dependency to matching versions. The IPC contract remains stable within major versions, but explicit version checks prevent serialization errors.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →