Fixes #3 BlueZ experimental mode is required for proper BLE connectivity. Without it, BlueZ attempts Classic Bluetooth (BR/EDR) connections instead of BLE (LE) connections, causing connection errors like "br-connection-profile-unavailable" and immediate disconnections after pairing. Changes: - install.sh: Automatically enables BlueZ experimental mode during installation - Detects BlueZ version (requires >= 5.49) - Creates systemd override to add -E flag to bluetoothd - Checks if already enabled to avoid duplicate configuration - Shows strong warning if user skips with --skip-experimental flag - Added --skip-experimental flag to opt-out (not recommended) - Updated help text to document new flag - tests/test_installer.sh: Added tests for experimental mode configuration - README.md: Documented BlueZ experimental mode in installation sections - Added to automated installation description - Added as required step in manual installation - Added troubleshooting section for BR/EDR connection errors - examples/config_example.toml: Added troubleshooting entry for BR/EDR errors The installer now: 1. Detects BlueZ version >= 5.49 (required for experimental mode) 2. Checks if already enabled (graceful skip) 3. Enables experimental mode by default unless --skip-experimental is used 4. Shows prominent warning if skipped (may cause BLE to break) 5. Handles edge cases (no systemd, old BlueZ, container environments) This addresses the root cause reported in issue #3 where devices were connecting then immediately disconnecting with BR/EDR profile errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| examples | ||
| src/RNS | ||
| tests | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| install.sh | ||
| LICENSE | ||
| pytest.ini | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| TESTING.md | ||
Reticulum BLE Interface
A Bluetooth Low Energy (BLE) interface for Reticulum Network Stack, enabling mesh networking over BLE without additional hardware on Linux devices.
⚠️ Platform: Linux-only (requires BlueZ 5.x for GATT server functionality) ✅ Tested on: Raspberry Pi Zero W
Features
- Zero dongle requirements: Works with built-in BLE radios (Raspberry Pi, Linux laptops, etc.)
- Auto-discovery: Automatically finds and connects to nearby Reticulum BLE nodes
- Multi-peer mesh: Supports up to 7 simultaneous connections for mesh networking (may support more, untested)
- Dual mode operation: Acts as both central (scanner/client) and peripheral (advertiser/server)
- Connection prioritization: RSSI-based smart peer selection with connection history tracking
- Packet fragmentation: Handles BLE MTU limitations (20-512 bytes) transparently
- Enhanced error handling: Retry logic, exponential backoff, connection recovery
- Power management: Three power modes (aggressive/balanced/saver) for battery efficiency or CPU limitations. Saver mode tested on Raspberry Pi Zero W.
Installation
Prerequisites:
- Python 3.8 or higher
- Reticulum Network Stack already installed (installation guide)
- Linux with BlueZ 5.x
Option A: Automated Installation (Recommended)
The installation script automatically detects your Reticulum setup and installs dependencies in the correct environment:
# Download and run installer
git clone https://github.com/torlando-tech/ble-reticulum.git
cd ble-reticulum
chmod +x install.sh
./install.sh
# For custom config directory:
# ./install.sh --config /path/to/custom/config
The script will:
- ✓ Detect if Reticulum is in a venv or system-wide
- ✓ Install system dependencies (BlueZ, dbus)
- ✓ Install Python packages in the correct environment
- ✓ Copy BLE interface files to
~/.reticulum/interfaces/(or custom config directory if specified) - ✓ Enable BlueZ experimental mode (required for proper BLE connectivity)
- ✓ Optionally set up Bluetooth permissions
BlueZ Experimental Mode: The installer automatically enables BlueZ experimental mode, which is required for proper BLE connectivity. This allows the BLE interface to use LE-specific connection methods instead of defaulting to Classic Bluetooth (BR/EDR), preventing connection errors like "br-connection-profile-unavailable".
To skip this configuration (not recommended):
./install.sh --skip-experimental
Option B: Manual Installation
1. Install System Dependencies
Debian/Ubuntu/Raspberry Pi OS:
sudo apt-get update
sudo apt-get install python3-pip python3-gi python3-dbus python3-cairo bluez
Arch Linux:
sudo pacman -S base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils
Why these packages?
base-devel: Build tools (gcc, make, meson) required for compiling PyGObjectgobject-introspection: Development files for GObject introspection (required for PyGObject compilation)python-dbus: D-Bus Python bindings for BlueZ communicationpython-cairo: Cairo graphics librarybluez/bluez-utils: Bluetooth stack and utilities for Linux
Note for Arch users: PyGObject is intentionally NOT installed as a system package on Arch due to version incompatibility (Arch has 3.54.5, but bluezero requires <3.52.0). Instead, pip will compile the compatible PyGObject version (3.50.2) during installation. This adds ~2 minutes to installation time but ensures compatibility.
2. Install Python Dependencies
IMPORTANT: Install in the same environment as Reticulum!
Since we installed system packages for PyGObject, dbus-python, and pycairo in step 1, we only need to install the pure-Python packages:
If Reticulum is in a virtual environment:
# Activate the same venv where Reticulum is installed
source /path/to/reticulum-venv/bin/activate
pip install bleak==1.1.1 bluezero
If Reticulum is installed system-wide:
# Install system-wide (may need sudo)
pip install bleak==1.1.1 bluezero
# OR
sudo pip install bleak==1.1.1 bluezero
Note: The system packages (python3-gi, python3-dbus, python3-cairo) provide PyGObject, dbus-python, and pycairo, eliminating the need for lengthy compilation from source.
3. Copy BLE Interface Files
# Copy to Reticulum's interface directory
mkdir -p ~/.reticulum/interfaces
cp src/RNS/Interfaces/BLE*.py ~/.reticulum/interfaces/
4. Enable BlueZ Experimental Mode (Required)
BlueZ experimental mode is required for proper BLE connectivity. Without it, BlueZ may attempt Classic Bluetooth (BR/EDR) connections instead of BLE (LE) connections, causing connection failures.
Enable experimental mode (BlueZ >= 5.49):
sudo systemctl edit bluetooth
Add these lines:
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd -E
Save and restart Bluetooth:
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
Verify it's enabled:
ps aux | grep bluetoothd
# Should show: /usr/lib/bluetooth/bluetoothd -E
5. Grant Bluetooth Permissions
For non-root operation:
sudo setcap 'cap_net_raw,cap_net_admin+eip' $(which python3)
Note: If Reticulum is in a venv, grant permissions to that Python:
sudo setcap 'cap_net_raw,cap_net_admin+eip' /path/to/venv/bin/python3
Quick Start
1. Configure Reticulum
Add the BLE interface to your Reticulum configuration (~/.reticulum/config):
[[BLE Interface]]
type = BLEInterface
enabled = yes
# Optional: customize device name
# device_name = My-Reticulum-Node
For detailed configuration options, see examples/config_example.toml.
Custom Config Directory: If you use a custom Reticulum config directory with --config, the BLE interface will automatically use that directory to find its companion modules. No additional configuration needed!
2. Start Reticulum
rnsd --verbose
The interface will:
- Start advertising as a peripheral (if enabled)
- Scan for nearby BLE peers
- Automatically connect to discovered peers
- Form a mesh network with other BLE nodes
3. Verify Operation
# Check interface status
rnstatus
# Monitor announces
rnid -a
Configuration
The BLE interface supports extensive configuration options. See examples/config_example.toml for a fully documented example with all available options.
Key Configuration Options
device_name: Advertised device name (auto-generated if not specified)service_uuid: BLE service UUID (must match on all devices)enable_peripheral: Accept incoming connections (default: yes)enable_central: Scan and connect to peers (default: yes)discovery_interval: How often to scan for new peers (default: 5.0 seconds)max_connections: Maximum simultaneous connections (default: 7)min_rssi: Minimum signal strength in dBm (default: -85)power_mode: Power management (aggressive/balanced/saver)
Testing
For detailed testing information, see TESTING.md.
Quick test using example script (no BLE hardware required):
cd examples
python ble_minimal_test.py test
Troubleshooting
No peers discovered
- Verify Bluetooth is enabled:
bluetoothctl show - Check
service_uuidmatches on all devices - Try
power_mode = aggressivefor faster discovery - Increase
min_rssito -90 for longer range
Connection timeouts
- Increase
connection_timeoutto 60 - Reduce
max_connectionsto 3-5 - Check for BLE/WiFi interference (both use 2.4 GHz)
- Verify peer is within range (typically 10-30m)
GATT server failed to start
- Ensure BlueZ 5.x is installed:
bluetoothd --version - Check Bluetooth permissions (see Installation → Manual Installation → step 4)
- Try
sudo rnsdtemporarily to verify (not recommended for production) - Set
enable_peripheral = noto disable peripheral mode
Permission denied errors
- Grant capabilities to Python (see Installation → Manual Installation → step 5)
- Or run with sudo:
sudo rnsd(not recommended)
BR/EDR connection errors (br-connection-profile-unavailable, ProfileUnavailable)
These errors occur when BlueZ attempts Classic Bluetooth (BR/EDR) connections instead of BLE (LE) connections. This is the most common BLE connection issue.
Symptoms:
- Devices connect then immediately disconnect
- Errors: "br-connection-profile-unavailable", "ProfileUnavailable"
- "ConnectDevice() unavailable" in logs
- Devices get blacklisted after multiple failures
Solution:
Enable BlueZ experimental mode (see Installation → Manual Installation → step 4). If you used the automated installer, re-run it without --skip-experimental.
Architecture
The BLE interface consists of four main components:
BLEInterface.py: Main interface implementation, handles discovery and connectionsBLEGATTServer.py: GATT server for peripheral mode (accepting connections)BLEFragmentation.py: Packet fragmentation/reassembly for BLE MTU limitsBLEAgent.py: Per-peer connection management
Development Setup
For contributors and developers who want to work on the BLE interface code itself.
Note: This setup is different from the production installation above. Use a virtual environment for development to avoid conflicts.
# Clone repository
git clone https://github.com/torlando-tech/ble-reticulum.git
cd ble-reticulum
# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate
# Install RNS (required for tests)
pip install rns
# Install all dependencies (runtime + development + testing)
pip install -r requirements-dev.txt
# Create package structure for tests
touch src/RNS/__init__.py
touch src/RNS/Interfaces/__init__.py
# Run tests
pytest
# Run tests with coverage
pytest --cov=src/RNS/Interfaces --cov-report=html
For detailed development and testing guidelines, see CONTRIBUTING.md and TESTING.md.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for:
- Code style guidelines
- Pull request process
- Bug report templates
- Feature request guidelines
Supporting
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Reticulum Network Stack by Mark Qvist
- Built using bleak for BLE central operations
- Built using bluezero for GATT server