Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hydroshift2

Unofficial Rust protocol and USB control library for the Lian Li HydroShift II LCD-C

CI License: MIT Rust 1.85+

No L-Connect process, DLL, service, or network connection is required.

Important

This is an independent, reverse-engineered project. It is not affiliated with, endorsed by, or supported by Lian Li. The implementation has been verified on the HydroShift II LCD-C 360N with USB ID 1CBE:A021.

What it controls

Surface Capability
Round LCD 480×480 JPEG background and transparent PNG overlay
LCD controls Brightness, 0°/90°/180°/270° rotation, clock/session setup
Pump ring 24 addressable RGB LEDs, static frames and uploaded animations
Cooling Pump target mapping from 1600–2500 RPM and three fan-control bytes
Transport Direct USB bulk endpoints 0x01 / 0x81

The crate exposes both a high-level [HydroShiftII] controller and a stateless [Protocol] packet encoder. USB, image encoding and bundled TinyUZ support are feature-gated.

Quick start

[dependencies]
hydroshift2 = { git = "https://github.com/andyjusa/hydroshift2-rs" }
use hydroshift2::{HydroShiftII, Rotation};

fn main() -> hydroshift2::Result<()> {
    // Claims the USB interface and clears retained vendor LCD layers.
    let mut device = HydroShiftII::open_and_initialize()?;

    device.set_lcd_brightness(220)?;
    device.set_rotation(Rotation::Degrees0)?;
    device.set_pump_speed(2025, [0, 0, 0])?;

    // One RGB frame uses the dependency-free Rust TinyUZ encoder.
    device.set_static_rgb([0, 232, 255], 0.8)?;

    // A 64-frame, 20 FPS loop is compressed once and played by the device.
    device.set_rainbow()?;
    Ok(())
}

Opening the device does not change its state:

use hydroshift2::HydroShiftII;

let device = HydroShiftII::open()?;
// Call initialize_lcd() only when you want to clear the retained LCD layers.
# Ok::<(), hydroshift2::Error>(())

Send an LCD image

use hydroshift2::HydroShiftII;

fn main() -> hydroshift2::Result<()> {
    let image = image::open("dashboard.png")?;
    let mut device = HydroShiftII::open_and_initialize()?;
    device.send_image(&image, 90)?;
    Ok(())
}

The hardware display is physically round, but its transmitted canvas is a square 480×480 image. Mask or compose the visible circle in your renderer.

RGB animation model

The pump ring does not need a host USB write for every animation frame. A batch of frames is TinyUZ-compressed, uploaded with command 0xFC, then played by the controller at the supplied interval. set_rainbow() uploads 64 frames with a 50 ms interval (20 FPS).

  • One-frame updates use the built-in pure-Rust encoder.
  • Multi-frame uploads use the pinned official TinyUZ 1.1.1 compressor on Windows because that representation is known to be accepted by the H2 firmware.
  • The executable is MIT-licensed, SHA-256 checked, embedded at build time, and extracted to %LOCALAPPDATA%/hydroshift2-rs/tinyuz/1.1.1/ when required.
  • Other platforms can pass TinyUzCli::from_path(...) to send_rgb_frames_with(...).

Protocol notes

Each control message begins with a 500-byte plaintext header. The header is DES-CBC encrypted with PKCS#7 padding, placed in a 512-byte envelope, and ends with A1 1A. Image and RGB payloads follow that envelope.

Command Purpose Payload detail
0x65 JPEG LCD background big-endian byte length at header 8..12
0x66 PNG LCD overlay big-endian byte length at header 8..12
0x0D LCD rotation one byte, 0..3
0x0E LCD brightness one byte, 0..255
0x33 device clock UTC date/time and display mode
0xFB pump/fan control 16-byte block with CRC-16/CCITT
0xFC 24-LED ring frames TinyUZ data + frame count + interval + LED count

Protocol::*_at variants accept an explicit timestamp for packet-capture comparison and deterministic tests.

Features

Feature Default Description
usb rusb discovery and bulk transport
image JPEG/PNG encoding and clean LCD initialization
bundled-tinyuz pinned Windows x64 TinyUZ for multi-frame RGB

Protocol-only consumers can disable everything:

hydroshift2 = {
  git = "https://github.com/andyjusa/hydroshift2-rs",
  default-features = false
}

Safety

  • Close L-Connect before claiming the USB interface. Two controllers writing to the same device will race and may leave stale LCD or RGB state.
  • Pump requests are clamped to the observed 1600–2500 RPM range.
  • open() only claims the interface; open_and_initialize() intentionally clears both retained LCD composition layers.
  • Treat all reverse-engineered hardware control as use-at-your-own-risk.

Examples and validation

cargo run --example probe
cargo run --example static_rgb
cargo run --example rainbow
cargo run --example lcd_image -- path\to\dashboard.png
cargo test --all-features

The original implementation is exercised in SpatialLume, where the LCD and ring are driven independently of L-Connect.

License

The Rust library is available under the MIT License. The bundled TinyUZ binary retains its upstream MIT license; see THIRD_PARTY_NOTICES.md.

About

Unofficial Rust protocol and USB control library for the Lian Li HydroShift II LCD-C

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages