A Python script that allows you to configure Wi-Fi credentials on a Raspberry Pi via Bluetooth Low Energy (BLE) using GATT characteristics. Perfect for headless Raspberry Pi setups where you need to connect to Wi-Fi without a keyboard/monitor.
🚀 Quick Start: Want to get started in 5 minutes? Check out QUICKSTART.md
- ✅ Advertises as a BLE peripheral device
- ✅ No pairing required (completely open for easy access)
- ✅ Set Wi-Fi SSID and password via BLE
- ✅ Real-time connection status updates
- ✅ Works with iOS (nRF Connect, LightBlue), Android, macOS, and Linux
- ✅ Uses standard GATT characteristics
- Raspberry Pi with built-in Bluetooth (Pi 3, 4, 5, Zero W, etc.)
- Or USB Bluetooth dongle
- Python 3.7+
- BlueZ 5.50+
- NetworkManager (nmcli)
- dbus-next Python library
Follow these steps to install and set up the BLE Wi-Fi provisioner on your Raspberry Pi (or any Linux system with Bluetooth).
First, make sure your system has the required Bluetooth packages and Python:
sudo apt-get update
sudo apt-get install -y bluetooth bluez python3-full python3-pipWhat this does:
bluetooth&bluez- The Linux Bluetooth stackpython3-full- Complete Python installation (needed for venv on newer systems)python3-pip- Python package installer
# Option A: Clone with git
git clone https://github.com/byrdsandbytes/beatnik-ble-wifi-provisioner.git
cd beatnik-ble-wifi-provisioner
# Option B: Download manually
# Download the repository as a ZIP and extract it, then:
cd beatnik-ble-wifi-provisionerNow run the automated setup script:
# Make the setup script executable (only needed once)
chmod +x setup-venv.sh
# Run the setup script
./setup-venv.shWhat this does:
- Creates a virtual environment in
venv/directory - Activates the virtual environment
- Upgrades pip to the latest version
- Installs all Python dependencies from
requirements.txt(currently justdbus-next)
You should see output like:
Creating Python virtual environment...
Activating virtual environment...
Installing dependencies...
...
✅ Setup complete!
Make sure the Bluetooth service is running:
sudo systemctl enable bluetooth
sudo systemctl start bluetooth
# Verify it's running
sudo systemctl status bluetoothYou should see active (running) in green.
Activate the virtual environment and run the script:
# Activate the virtual environment
source venv/bin/activate
# Run the BLE server (requires sudo for Bluetooth access)
sudo venv/bin/python3 src/ble-server.pyImportant: Even when using sudo, you must specify the full path to the Python interpreter in the venv (venv/bin/python3), otherwise sudo will use the system Python which doesn't have the packages installed.
You should see output like:
INFO:root:Using Bluetooth adapter: /org/bluez/hci0
INFO:root:Adapter powered on
INFO:root:Adapter set to always discoverable
INFO:root:Pairing disabled - iOS connects without bonding
INFO:root:GATT application registered successfully.
INFO:root:Advertising as 'Pi-Provisioner'...
✅ Success! Your Raspberry Pi is now advertising as a BLE device.
See the Connecting from Your Device section below for instructions on how to connect and provision Wi-Fi.
Every time you want to run the BLE provisioning server:
# 1. Navigate to the project directory
cd beatnik-ble-wifi-provisioner
# 2. Activate the virtual environment
source venv/bin/activate
# 3. Run the server with sudo
sudo venv/bin/python3 src/ble-server.pyWhy sudo venv/bin/python3?
sudois required for Bluetooth low-level accessvenv/bin/python3ensures you're using the Python with installed packages- Just
sudo python3would use the system Python without your packages!
To stop the server:
Press Ctrl+C in the terminal.
You should see output like:
INFO:root:Auto-accept agent registered
INFO:root:Using Bluetooth adapter: /org/bluez/hci0
INFO:root:Adapter powered on
INFO:root:Adapter set to always discoverable
INFO:root:Pairing disabled - iOS connects without bonding
INFO:root:GATT application registered successfully.
INFO:root:Advertising as 'Pi-Provisioner'...
-
Download a BLE app (required - iOS Settings won't work):
- nRF Connect by Nordic Semiconductor (recommended)
- LightBlue by Punch Through
-
Open the BLE app and scan for devices
-
Look for "Pi-Provisioner"
-
Tap to connect (no pairing needed)
- Download nRF Connect from Google Play
- Scan and connect to "Pi-Provisioner"
- Download nRF Connect or use
bluetoothctl - Connect to "Pi-Provisioner"
Once connected, you'll see a service with 4 characteristics:
| Characteristic | UUID | Type | Description |
|---|---|---|---|
| SSID | 12345678-1234-5678-1234-56789abcdef1 |
Write | Write your Wi-Fi network name |
| Password | 12345678-1234-5678-1234-56789abcdef2 |
Write | Write your Wi-Fi password |
| Connect | 12345678-1234-5678-1234-56789abcdef3 |
Write | Write any value to trigger connection |
| Status | 12345678-1234-5678-1234-56789abcdef4 |
Read/Notify | Read connection status |
- Connect to "Pi-Provisioner"
- Expand the service (UUID:
12345678-1234-5678-1234-56789abcdef0) - Write SSID:
- Tap the "Write" button on the SSID characteristic
- Select "Text" format
- Enter your Wi-Fi network name (e.g., "MyHomeWiFi")
- Send
- Write Password:
- Tap "Write" on the Password characteristic
- Select "Text" format
- Enter your Wi-Fi password
- Send
- Enable Notifications on Status characteristic (optional but recommended)
- Trigger Connection:
- Tap "Write" on the Connect characteristic
- Send any value (e.g., "1")
- Watch Status characteristic for updates:
- "Connecting to MyHomeWiFi..."
- "Success! Connected." or "Failed: Bad Password?"
- BLE Advertisement: The script advertises itself as "Pi-Provisioner"
- GATT Service: Exposes a custom service with 4 characteristics
- Write Credentials: Client writes SSID and password
- Connection Trigger: Writing to Connect characteristic triggers
nmclito connect - Status Updates: Status characteristic updates in real-time with connection progress
Edit line 293 in src/ble-server.py:
self.local_name = "Pi-Provisioner" # Change this to your preferred nameEdit lines 27-31 in src/ble-server.py:
SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef0" # Your custom service UUID
SSID_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef1"
PASS_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef2"
CONNECT_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef3"
STATUS_CHAR_UUID = "12345678-1234-5678-1234-56789abcdef4"To make the BLE provisioner start automatically when your Raspberry Pi boots:
Step 1: Create a systemd service file:
sudo nano /etc/systemd/system/ble-provisioning.serviceStep 2: Add this configuration (update paths if needed):
[Unit]
Description=BLE Wi-Fi Provisioning Service
After=bluetooth.service network.target
Requires=bluetooth.service
[Service]
Type=simple
# Update this path to match your installation location
ExecStart=/home/pi/beatnik-ble-wifi-provisioner/venv/bin/python3 /home/pi/beatnik-ble-wifi-provisioner/src/ble-server.py
WorkingDirectory=/home/pi/beatnik-ble-wifi-provisioner
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.targetStep 3: Enable and start the service:
# Reload systemd to recognize the new service
sudo systemctl daemon-reload
# Enable the service to start on boot
sudo systemctl enable ble-provisioning.service
# Start the service now
sudo systemctl start ble-provisioning.serviceStep 4: Check that it's running:
# Check service status
sudo systemctl status ble-provisioning.service
# View live logs
sudo journalctl -u ble-provisioning.service -fManaging the service:
# Stop the service
sudo systemctl stop ble-provisioning.service
# Restart the service
sudo systemctl restart ble-provisioning.service
# Disable auto-start on boot
sudo systemctl disable ble-provisioning.service
# View recent logs
sudo journalctl -u ble-provisioning.service -n 50"No module named 'dbus_next'" when running with sudo
# Make sure you're using the venv Python, not system Python:
sudo venv/bin/python3 src/ble-server.py
# NOT just:
sudo python3 src/ble-server.py # ❌ This uses system Python"venv/bin/python3: No such file or directory"
# The virtual environment wasn't created. Run setup again:
./setup-venv.sh"Permission denied: ./setup-venv.sh"
# Make the script executable:
chmod +x setup-venv.sh
./setup-venv.shWant to recreate the virtual environment from scratch?
# Delete the old venv
rm -rf venv
# Run setup again
./setup-venv.sh**"Failed to introspect BlueZ service"
sudo systemctl start bluetooth
sudo systemctl status bluetooth- Make sure Bluetooth is enabled
- Use a BLE scanning app (not iOS Settings)
- Try restarting the script
- Check if advertising:
sudo hcitool lescan
- On iOS: Forget the device in Settings → Bluetooth if it appears there
- Turn Bluetooth OFF and ON
- Restart the script
# Check if Bluetooth hardware is detected
hciconfig
# Should show hci0 or similar
# If not, check if rfkill is blocking it
sudo rfkill list
sudo rfkill unblock bluetooth- Make sure you're using a BLE app (not iOS Settings)
- Check that the script is running with
sudo - Look at script logs for errors
- iOS Settings → Bluetooth will NOT work for accessing GATT services
- You MUST use a dedicated BLE app like nRF Connect or LightBlue
- This is a limitation of iOS, not this script
- Even after pairing, you need an app to read/write characteristics
⚠️ This implementation has no security - anyone nearby can connect- Credentials are transmitted without encryption
- Suitable for initial setup in a controlled environment
- For production, consider adding:
- BLE bonding/pairing
- Encrypted characteristics
- Authentication mechanisms
- Time-limited operation (only allow provisioning for 5 minutes after boot)
- Uses NetworkManager (
nmcli) for Wi-Fi configuration - Most modern Raspberry Pi OS versions include this by default
- If using a different network manager, modify the
attempt_connection()function
Uncomment line 70 to stop advertising after successful connection:
# In a real app, you might stop advertising here
# Add code to unregister advertisementModify the attempt_connection() function (lines 48-78) to:
- Use different network managers (wpa_supplicant, etc.)
- Add VPN configuration
- Set static IP addresses
- Configure additional network settings
Built with:
- dbus-next - Python D-Bus library
- BlueZ - Linux Bluetooth stack
- NetworkManager - Network configuration
MIT License - feel free to use and modify for your projects!
For issues and questions:
- Check the Troubleshooting section above
- Enable DEBUG logging: Change
logging.INFOtologging.DEBUGon line 367 - Check BlueZ version:
bluetoothctl --version(requires 5.50+) - Test with nRF Connect first before trying other apps
# 1. Install system packages
sudo apt-get update
sudo apt-get install -y bluetooth bluez python3-full python3-pip
# 2. Clone the repository
git clone https://github.com/byrdsandbytes/beatnik-ble-wifi-provisioner.git
cd beatnik-ble-wifi-provisioner
# 3. Run setup script
chmod +x setup-venv.sh
./setup-venv.sh
# 4. Enable Bluetooth
sudo systemctl enable bluetooth
sudo systemctl start bluetoothcd beatnik-ble-wifi-provisioner
source venv/bin/activate
sudo venv/bin/python3 src/ble-server.py# Check Bluetooth status
sudo systemctl status bluetooth
# View Bluetooth devices
hciconfig
# Restart Bluetooth
sudo systemctl restart bluetooth
# Recreate virtual environment
rm -rf venv && ./setup-venv.sh
# Check if process is running
ps aux | grep ble-serverPro Tip: For production IoT devices, consider building a companion mobile app using:
- iOS: CoreBluetooth framework
- Android: Android BLE APIs
This provides a much better user experience than requiring users to install third-party BLE apps!