Python client library for the Buttplug Intimate Hardware Control Protocol (v4).
pip install buttplugOr with uv:
uv add buttplug-
Install and start Intiface Central - This is the server that connects to your devices.
-
Connect and control devices:
import asyncio
from buttplug import ButtplugClient, DeviceOutputCommand, OutputType
async def main():
# Create a client
client = ButtplugClient("My App")
# Connect to Intiface Central (default address)
await client.connect("ws://127.0.0.1:12345")
# Scan for devices
await client.start_scanning()
await asyncio.sleep(5) # Wait for devices to be found
await client.stop_scanning()
# Control devices
for device in client.devices.values():
print(f"Found: {device.name}")
if device.has_output(OutputType.VIBRATE):
await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 0.5))
await asyncio.sleep(2)
await device.stop()
await client.disconnect()
asyncio.run(main())- Simple API: Unified
run_output()method for all output types - Full Protocol Support: Implements Buttplug protocol v4
- Type Hints: Full typing support for IDE autocomplete and type checking
- Async/Await: Modern Python async API
- Event Callbacks: Get notified when devices connect/disconnect
from buttplug import DeviceOutputCommand, OutputType
# Check device capabilities and send commands
if device.has_output(OutputType.VIBRATE):
await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 0.75))
if device.has_output(OutputType.ROTATE):
await device.run_output(DeviceOutputCommand(OutputType.ROTATE, 0.5))
if device.has_output(OutputType.POSITION_WITH_DURATION):
await device.run_output(
DeviceOutputCommand(OutputType.POSITION_WITH_DURATION, 1.0, duration=500)
)
# Read sensors
if device.has_input(InputType.BATTERY):
battery = await device.battery()
print(f"Battery: {battery * 100:.0f}%")
# Stop device
await device.stop()# Set up callbacks before connecting
client.on_device_added = lambda d: print(f"Connected: {d.name}")
client.on_device_removed = lambda d: print(f"Disconnected: {d.name}")
client.on_scanning_finished = lambda: print("Scan complete")
client.on_server_disconnect = lambda: print("Server disconnected!")
# Async callbacks are also supported
async def on_device_added(device):
if device.has_output(OutputType.VIBRATE):
await device.run_output(DeviceOutputCommand(OutputType.VIBRATE, 0.25))
client.on_device_added = on_device_addedSee the examples/ directory for more detailed examples:
application.py- Complete application workflowconnection.py- Connecting to a serverdevice_control.py- Vibrate, rotate, and position commandsdevice_enumeration.py- Discovering devicesdevice_info.py- Inspecting device featuressensors.py- Battery and signal strengtherrors.py- Error handling
To run examples from within the repo:
uv sync
uv run python examples/application.py- Python 3.10+
- Intiface Central or another Buttplug server
- Discord - Community chat and support
- GitHub Issues - Bug reports and feature requests
- Patreon / GitHub Sponsors - Support development
BSD 3-Clause. See LICENSE for details.