Device
Represents a single device connected to a Buttplug server.
The Device class provides typed methods for controlling outputs (vibration, rotation, position, etc.) and reading or subscribing to input sensors. Device instances are created internally by ButtplugClient when devices are discovered.
client.on("deviceAdded", ({ device }) => {
console.log(device.name, device.features);
await device.vibrate(50);
});Properties
index
get index(): numberServer-assigned device index.
name
get name(): stringInternal device name from firmware.
displayName
get displayName(): string | nullUser-facing display name, or null if the server did not provide one.
messageTimingGap
get messageTimingGap(): numberMinimum interval in milliseconds between messages recommended by the server. Commands sent faster than this interval may be dropped.
features
get features(): DeviceFeaturesParsed input and output feature descriptors for this device. See DeviceFeatures for the shape.
canRotate
get canRotate(): booleanWhether this device supports any form of rotation output (Rotate or RotateWithDirection).
canPosition
get canPosition(): booleanWhether this device supports any form of position output (Position or HwPositionWithDuration).
Output Methods
All scalar output methods accept either a single number (applied to all motors/actuators) or a FeatureValue[] array for per-feature control.
vibrate
vibrate(intensity: number | FeatureValue[]): Promise<void>Sets vibration intensity on all or individual motors.
| Parameter | Type | Description |
|---|---|---|
intensity | number | FeatureValue[] | Single value for all motors, or per-motor entries |
Throws: DeviceError if the device does not support vibration.
// All motors at 50%
await device.vibrate(50);
// Per-motor control
await device.vibrate([
{ index: 0, value: 80 },
{ index: 1, value: 40 },
]);oscillate
oscillate(speed: number | FeatureValue[]): Promise<void>Sets oscillation speed on all or individual motors.
Throws: DeviceError if the device does not support oscillation.
constrict
constrict(value: number | FeatureValue[]): Promise<void>Sets constriction pressure on all or individual actuators.
Throws: DeviceError if the device does not support constriction.
spray
spray(value: number | FeatureValue[]): Promise<void>Controls spray output on all or individual actuators.
Throws: DeviceError if the device does not support spraying.
temperature
temperature(value: number | FeatureValue[]): Promise<void>Sets temperature on all or individual actuators.
Throws: DeviceError if the device does not support temperature control.
led
led(value: number | FeatureValue[]): Promise<void>Controls LED brightness on all or individual actuators.
Throws: DeviceError if the device does not support LED control.
rotate
Rotation has two overloads:
// Uniform speed on all motors
rotate(speed: number, options?: { clockwise?: boolean }): Promise<void>
// Per-motor control
rotate(values: RotationValue[]): Promise<void>Sets rotation speed and direction. Automatically selects RotateWithDirection if the device supports it, falling back to Rotate otherwise.
| Parameter | Type | Description |
|---|---|---|
speed | number | Single speed for all motors |
options.clockwise | boolean | Direction (defaults to true) |
values | RotationValue[] | Per-motor entries with speed, direction, and index |
Throws: DeviceError if the device does not support rotation.
await device.rotate(70, { clockwise: false });
await device.rotate([
{ index: 0, speed: 80, clockwise: true },
{ index: 1, speed: 40, clockwise: false },
]);position
Position has two overloads:
// Uniform position on all axes
position(position: number, options: { duration: number }): Promise<void>
// Per-axis control
position(values: PositionValue[]): Promise<void>Moves all axes to a position over a given duration. Automatically selects HwPositionWithDuration if the device supports it.
| Parameter | Type | Description |
|---|---|---|
position | number | Single position value for all axes |
options.duration | number | Movement duration in milliseconds (required for uniform) |
values | PositionValue[] | Per-axis entries with position, duration, and index |
Throws: DeviceError if the device does not support position control.
await device.position(80, { duration: 500 });
await device.position([
{ index: 0, position: 100, duration: 300 },
]);stop
stop(options?: DeviceStopOptions): Promise<void>Stops activity on this device. Without options, stops all features. Can target a specific feature index or filter by input/output type.
Prop
Type
Throws: DeviceError if the specified feature index does not exist.
await device.stop();
await device.stop({ featureIndex: 0 });
await device.stop({ outputs: true, inputs: false });output
output(options: DeviceOutputOptions): Promise<void>Sends a raw output command to a specific feature. Values are validated against the feature's declared range and clamped if out of bounds.
Prop
Type
Throws: DeviceError if no matching output feature exists at the given index.
await device.output({
featureIndex: 0,
command: { Vibrate: { Value: 50 } },
});Sensor Methods
readSensor
readSensor(type: InputType, sensorIndex?: number): Promise<number>Performs a one-shot read of a sensor value.
| Parameter | Type | Description |
|---|---|---|
type | InputType | Sensor type (e.g. "Battery", "RSSI") |
sensorIndex | number | Index if the device has multiple sensors of the same type (default 0) |
Returns: The numeric sensor value.
Throws: DeviceError if the sensor does not exist or does not support reading.
const battery = await device.readSensor("Battery");
console.log(`Battery: ${battery}%`);subscribeSensor
subscribeSensor(
type: InputType,
callback: (value: number) => void,
sensorIndex?: number
): Promise<() => Promise<void>>Subscribes to continuous sensor readings.
| Parameter | Type | Description |
|---|---|---|
type | InputType | Sensor type to subscribe to |
callback | (value: number) => void | Called with the numeric sensor value on each new reading |
sensorIndex | number | Index if multiple sensors of the same type (default 0) |
Returns: An async unsubscribe function that stops the subscription.
Throws: DeviceError if the sensor does not exist or does not support subscriptions.
const unsubscribe = await device.subscribeSensor(
"Battery",
(value) => console.log(value)
);
// Later
await unsubscribe();unsubscribe
unsubscribe(type: InputType, sensorIndex?: number): Promise<void>Explicitly unsubscribes from a sensor subscription by type and sensor index.
Throws: DeviceError if the sensor does not exist at the given index.
Capability Checks
canOutput
canOutput(type: OutputType): booleanChecks whether this device supports a given output type.
if (device.canOutput("Vibrate")) {
await device.vibrate(50);
}canRead
canRead(type: InputType): booleanChecks whether this device can perform a one-shot read of a given sensor type.
canSubscribe
canSubscribe(type: InputType): booleanChecks whether this device supports subscriptions for a given sensor type.