Control Bluetooth-enabled LINAK desks from the command line.
oxlinak talks to the desk over BLE (via btleplug).
Run it one-off to move the desk or read its state, or keep it running as a daemon that holds
the BLE connection open so subsequent commands are instant — no reconnect overhead.
nix run github:tophcodes/oxlinak -- scanThe repo ships a Nix flake:
nix develop
cargo build --releaseoxlinak scan # list nearby desks → grab the MAC address
oxlinak check # connect and print base height, capabilities, user id
oxlinak move 1080 # move the desk to 1080 mm
oxlinak monitor # print live position updates until Ctrl-C
oxlinak server # start the daemon — holds BLE connection for fast IPCWhen the daemon is running, move routes through it instead of opening a new BLE connection
each time. Logging honours RUST_LOG (defaults to info), e.g. RUST_LOG=debug oxlinak server.
oxlinak reads a YAML config from ~/.config/oxlinak/config.yaml (override with --config <path>).
If the file is missing, the first check/move/server run writes a template and asks you
to fill in your desk's mac (get it from oxlinak scan).
mac: "E6:BF:DF:33:0B:7C" # your desk's MAC — find it with `oxlinak scan`
# Optional: clamp the height range.
limits:
min: 625
max: 910
# Optional: MQTT bridge for Home Assistant integration.
mqtt:
host: "mqtt.example.com"
port: 1883
username: "oxlinak" # optional
password: "secret" # optional
discovery:
enabled: true # publish Home Assistant MQTT discovery configs
prefix: "homeassistant" # discovery topic prefix (must match HA's setting)Configure mqtt in the config and run the daemon. With discovery.enabled: true, oxlinak
publishes auto-discovery configs and a LINAK Desk device appears in Home Assistant with:
- Height — a read-only sensor (mm) that follows the desk live.
- Target height — a
numberentity; setting it moves the desk.
Presets (sit/stand, meeting, …) are intentionally not exposed — build them in Home
Assistant yourself (e.g. a script or button that writes a height to the number entity).
An availability topic (online/offline via MQTT LWT) reflects the daemon/desk connection state.
The desk's BLE height encoding (RAW_PER_MM, BASE_HEIGHT_MM in src/desk.rs) and the
LINAK UUID base were calibrated against the author's desk. Different LINAK models/firmware may
differ; adjust the constants if your desk moves to the wrong height.
See repository.