NodeNav now includes full Bluetooth device management for Linux systems! You can discover, pair, connect, and control Bluetooth devices directly from the application without needing to use system settings.
This implementation uses BlueZ (the official Linux Bluetooth stack) via D-Bus for direct hardware access and complete control.
✅ Device Discovery - Scan for nearby Bluetooth devices
✅ Device Pairing - Pair with discovered devices
✅ Connect/Disconnect - Connect to paired devices directly from the app
✅ Device Management - Remove paired devices
✅ Real-time Updates - Live device status updates
✅ Complete Control - No need to use system Bluetooth settings
- Linux Operating System (tested on Ubuntu, Debian, Fedora, Arch)
- BlueZ Bluetooth Stack (pre-installed on most Linux distributions)
- D-Bus (system message bus - pre-installed on most systems)
- Bluetooth Hardware (built-in or USB Bluetooth adapter)
The application needs permission to access the Bluetooth adapter via D-Bus. There are two ways to handle this:
sudo npm run electron-devCreate a D-Bus policy file to allow your user to access Bluetooth:
sudo nano /etc/dbus-1/system.d/bluetooth-access.confAdd the following content (replace YOUR_USERNAME with your actual username):
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="YOUR_USERNAME">
<allow send_destination="org.bluez"/>
<allow send_interface="org.bluez.Adapter1"/>
<allow send_interface="org.bluez.Device1"/>
<allow send_interface="org.freedesktop.DBus.Properties"/>
<allow send_interface="org.freedesktop.DBus.ObjectManager"/>
</policy>
</busconfig>Reload D-Bus configuration:
sudo systemctl reload dbusOn some systems, you may need to add your user to the bluetooth group:
sudo usermod -a -G bluetooth $USERThen log out and log back in for the changes to take effect.
┌─────────────────────────────────────┐
│ NodeNav React Frontend │
│ (BluetoothSettings.jsx) │
└──────────────┬──────────────────────┘
│ REST API
┌──────────────▼──────────────────────┐
│ Express Server (server.js) │
│ /api/bluetooth/* endpoints │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ bluetooth-service.js │
│ (Platform Detection) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ bluetooth-device-linux.js │
│ (BlueZ D-Bus Interface) │
└──────────────┬──────────────────────┘
│ D-Bus Protocol
┌──────────────▼──────────────────────┐
│ BlueZ (org.bluez) │
│ Linux Bluetooth Stack │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Bluetooth Hardware Adapter │
└─────────────────────────────────────┘
The implementation uses the following D-Bus interfaces:
- org.bluez.Adapter1 - Bluetooth adapter control (scanning, etc.)
- org.bluez.Device1 - Individual device control (pair, connect, etc.)
- org.freedesktop.DBus.ObjectManager - Device discovery and monitoring
- org.freedesktop.DBus.Properties - Reading device/adapter properties
-
Make sure Bluetooth is enabled on your system:
# Check if Bluetooth is running systemctl status bluetooth # If not running, start it sudo systemctl start bluetooth
-
Start NodeNav:
npm run electron-dev
-
Navigate to the Bluetooth Settings page in the app
- Click the "Start Scan" button
- Nearby Bluetooth devices will appear in the "Available Devices" section
- Scanning automatically stops after 30 seconds (or click "Stop Scan")
- Find the device you want to pair in the "Available Devices" section
- Click the "Pair" button
- If the device requires confirmation (PIN, passkey, etc.), you may need to:
- Check the device for a PIN/passkey
- Confirm the pairing on both devices
- Some devices pair automatically without confirmation
- Once paired, the device will show a "Connect" button
- Click "Connect" to establish a connection
- The device will move to the "Connected Devices" section
- Connected devices can be used for audio, input, or other Bluetooth profiles
- Click "Disconnect" to disconnect while keeping the pairing
- Click "Unpair" to completely remove the device
The following REST API endpoints are available:
GET /api/bluetooth/devices- Get all discovered devicesGET /api/bluetooth/devices/connected- Get only connected devicesGET /api/bluetooth/adapter- Get Bluetooth adapter information
POST /api/bluetooth/scan/start- Start scanning for devicesPOST /api/bluetooth/scan/stop- Stop scanningPOST /api/bluetooth/devices/:address/pair- Pair with a devicePOST /api/bluetooth/devices/:address/connect- Connect to a devicePOST /api/bluetooth/devices/:address/disconnect- Disconnect from a deviceDELETE /api/bluetooth/devices/:address- Unpair a device
GET /api/bluetooth/history- Get Bluetooth command historyDELETE /api/bluetooth/history- Clear command history
Cause: BlueZ is not running or no Bluetooth adapter is present
Solution:
# Check if BlueZ is running
systemctl status bluetooth
# Start BlueZ
sudo systemctl start bluetooth
# Enable BlueZ to start on boot
sudo systemctl enable bluetooth
# Check if adapter is detected
hciconfigCause: Permission denied or adapter is busy
Solution:
- Make sure you have the correct D-Bus permissions (see Permissions section)
- Try stopping any other Bluetooth managers:
# Check for other Bluetooth processes ps aux | grep bluetooth # Kill bluetoothctl if running killall bluetoothctl
Cause: Device not in pairing mode, PIN required, or already paired
Solution:
- Make sure the device is in pairing/discoverable mode
- Check if the device is already paired:
bluetoothctl devices
- If already paired, try unpairing first from the app
- For devices requiring a PIN, check the device manual
Cause: Missing Bluetooth profile support or driver issues
Solution:
-
Check if required Bluetooth profiles are installed:
# For audio devices sudo apt install pulseaudio-module-bluetooth # Restart PulseAudio pulseaudio -k pulseaudio --start
-
Check device capabilities:
bluetoothctl info [device_address]
Cause: User doesn't have permission to access BlueZ via D-Bus
Solution: Follow the Permission setup in the Requirements section above
If you want to test the app without Bluetooth hardware, you can create a virtual Bluetooth adapter:
# Load dummy Bluetooth module
sudo modprobe btusb
sudo modprobe bluetooth
# Or use vhci for virtual HCI
sudo modprobe hci_vhci- ✅ Linux - Full native support via BlueZ/D-Bus (this guide)
- ✅ Windows - Native support via PowerShell
⚠️ macOS - Simulation mode (limited OS access)
The implementation automatically detects device types using multiple methods:
- Icon property from BlueZ (most reliable)
- Device name pattern matching
- Bluetooth device class (major/minor class codes)
Supported device types:
- Phone
- Headphones/Earbuds
- Speaker
- Computer
- Input devices (keyboard, mouse)
- Audio devices
- Unknown (generic)
The implementation uses D-Bus signals to receive real-time device updates:
- InterfacesAdded - New devices discovered
- InterfacesRemoved - Devices removed
- PropertiesChanged - Device properties updated (connection state, etc.)
- Scans use the default BlueZ discovery filter
- Auto-stops after 30 seconds to conserve battery
- Discovery filter settings:
- Transport: auto (BR/EDR and LE)
- DuplicateData: false (reduce redundant discoveries)
-
D-Bus Access: The app requires D-Bus access to BlueZ, which is a system-level service. Use proper D-Bus policies in production.
-
Bluetooth Security: Always verify device identity before pairing with sensitive devices.
-
PIN/Passkey: Some devices require PIN confirmation. The app relies on BlueZ's agent system for pairing authentication.
-
User Permissions: Consider running the app with user-level permissions using D-Bus policies rather than root access.
The Linux Bluetooth implementation is modular and easy to extend:
- bluetooth-device-linux.js - Core BlueZ/D-Bus implementation
- bluetooth-service.js - Platform detection and service loading
- server.js - REST API endpoints
- BluetoothSettings.jsx - React UI component
Enable verbose BlueZ logging:
# Edit BlueZ service
sudo systemctl edit bluetooth
# Add these lines:
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd -d
# Restart BlueZ
sudo systemctl restart bluetooth
# View logs
journalctl -u bluetooth -fYou can test D-Bus communication manually:
# List available adapters
dbus-send --system --print-reply --dest=org.bluez / org.freedesktop.DBus.ObjectManager.GetManagedObjects
# Start discovery
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.bluez.Adapter1.StartDiscoveryFor issues, questions, or contributions, please visit the GitHub repository.
Note: This implementation provides direct hardware access to Bluetooth via BlueZ. Make sure to follow security best practices and properly manage device permissions in production environments.