buttplug-py
Python client library for the Buttplug Intimate Hardware Control Protocol (v4).
Installation
pip install buttplug
Or with uv:
uv add buttplug
Quick Start
-
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())
Features
- 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
Device Control
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()
Event Handling
# 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_added
Examples
See 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
Requirements
- Python 3.10+
- Intiface Central or another Buttplug server
Documentation
Support
- Discord - Community chat and support
- GitHub Issues - Bug reports and feature requests
- Patreon / GitHub Sponsors - Support development
License
BSD 3-Clause. See LICENSE for details.
Metadata
Release files for buttplug 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| buttplug-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for buttplug-1.0.0-py3-none-any.whl |
Release files / buttplug-1.0.0-py3-none-any.whl
| Download URL | buttplug-1.0.0-py3-none-any.whl |
|---|---|
| Size | 24.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7ef8db48762082106f1a1044c3bb2bad050ec6516c1ed00471032756553d476e
|
|
BLAKE2b-256 checksum How to use checksums |
b3802790e317d6567ca3f85a6dca31e430cfa4b08231d7a6f99d17316df2484e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Security for buttplug 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.