SimplePyBLE
SimplePyBLE provides Python bindings for SimpleBLE, a fully cross-platform Bluetooth Low Energy (BLE) library written in C++. It is designed for simplicity and ease of use, offering a consistent API across Windows, macOS, and Linux, with some support for iOS and Android. The library is currently at version 0.12.1 and maintains an active release cadence, with frequent updates addressing features, stability, and bug fixes.
Common errors
-
FileNotFoundError: [WinError 2] The system cannot find the file specified
cause This error typically occurs during `pip install simplepyble` on Windows, especially with newer Python versions (e.g., 3.13), indicating that necessary C++ build tools or SDK components are missing for compiling the underlying C++ library.fixEnsure that the 'Desktop development with C++' workload is installed in Visual Studio, including 'MSVC v143 - VS 2022 C++ x64/x86 build tools' and 'Windows 10/11 SDK'. If problems persist, consider trying a slightly older Python version for which pre-built wheels might be available. -
DLL load failed while importing _simplepyble: The specified module could not be found.
cause This error appears when attempting to `import simplepyble` on Windows, even after a seemingly successful installation. It means the Python bindings (`_simplepyble.pyd`) cannot find required runtime DLLs on the system's PATH, such as Visual C++ Redistributables.fixInstall the latest Microsoft Visual C++ Redistributable for your system (x64 and/or x86) from the official Microsoft website. Ensure any other system-level dependencies are correctly installed and visible in the system's PATH. -
ERROR: Failed building wheel for simplepyble
cause During `pip install simplepyble` on Linux, this indicates a failure to compile the C++ backend. A common reason is missing system development headers, particularly for D-Bus.fixInstall the necessary development packages. For Debian/Ubuntu-based systems, run: `sudo apt-get update && sudo apt-get install libdbus-1-dev`. Adapt for other distributions (e.g., `dnf install dbus-devel` on Fedora, `pacman -S dbus` on Arch). -
No adapters found
cause When `Adapter.get_adapters()` returns an empty list or your program immediately exits with this message, it usually means no Bluetooth adapter is active, available, or the application lacks the necessary permissions to access it.fixVerify that your Bluetooth hardware is enabled and turned on. On Linux, ensure your user has permissions to access Bluetooth devices (e.g., `sudo usermod -a -G bluetooth $USER` and reboot). Restart the Bluetooth service if necessary (e.g., `sudo systemctl restart bluetooth`).
Warnings
- breaking As of v0.9.0 (January 2025), SimpleBLE (and thus SimplePyBLE) has changed its license to Business Source License 1.1 (BUSL-1.1). Commercial use requires a commercial license, though free licenses are offered for small projects. Ensure your project's licensing is compatible.
- gotcha Versions prior to v0.10.3 (June 2025) and v0.10.2 (June 2025) experienced several deadlocks and GIL issues within the Python bindings, particularly on Windows when interacting with WinRT threading models. This could lead to application freezes or crashes.
- gotcha The `simplepyble.aio` module, providing an `asyncio`-compatible API, was introduced in v0.12.1 (February 2026). If you are using an older version or trying to implement asynchronous operations with the synchronous API, you might encounter blocking behavior or need to manually manage threads.
Install
-
pip install simplepyble
Imports
- Adapter
from simplepyble import Adapter
- Adapter
from simplepyble.aio import Adapter
Quickstart
import asyncio
from simplepyble.aio import Adapter
async def main():
adapters = Adapter.get_adapters()
if not adapters:
print("No adapters found. Ensure Bluetooth is on and permissions are granted.")
return
# Use the first adapter found
adapter = adapters[0]
print(f"Selected adapter: {adapter.identifier()} [{adapter.address()}]")
# Use the adapter within an async context manager
async with adapter:
print("Scanning for 5 seconds...")
await adapter.scan_for(5000) # Scan for 5000 milliseconds
peripherals = adapter.scan_get_results()
if not peripherals:
print("No peripherals found.")
return
print("Found peripherals:")
for i, peripheral in enumerate(peripherals):
print(f" [{i}] {peripheral.identifier()} [{peripheral.address()}] - Connectable: {peripheral.is_connectable()}")
# Example: Connect to the first connectable peripheral found
connectable_peripherals = [p for p in peripherals if p.is_connectable()]
if connectable_peripherals:
selected_peripheral = connectable_peripherals[0]
print(f"Attempting to connect to: {selected_peripheral.identifier()}")
await selected_peripheral.connect()
print(f"Successfully connected to {selected_peripheral.identifier()}")
# Discover services and characteristics (example)
services = selected_peripheral.services()
for service in services:
print(f" Service: {service.uuid()}")
for characteristic in service.characteristics():
print(f" Characteristic: {characteristic.uuid()} (Can Read: {characteristic.can_read()})")
await selected_peripheral.disconnect()
print(f"Disconnected from {selected_peripheral.identifier()}")
else:
print("No connectable peripherals found to demonstrate connection.")
if __name__ == "__main__":
asyncio.run(main())