From 0e00fbf2d6130bf8761742a7a656f62690cb1246 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Tue, 28 Oct 2025 23:25:52 -0400 Subject: [PATCH 1/6] feat: enable BlueZ experimental mode by default to fix BLE connection issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 54 ++++++++++++- examples/config_example.toml | 13 +++ install.sh | 148 ++++++++++++++++++++++++++++++++++- tests/test_installer.sh | 44 +++++++++++ 4 files changed, 252 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a94ac7f..51ca23a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,15 @@ The script will: 2. ✓ Install system dependencies (BlueZ, dbus) 3. ✓ Install Python packages in the correct environment 4. ✓ Copy BLE interface files to `~/.reticulum/interfaces/` (or custom config directory if specified) -5. ✓ Optionally set up Bluetooth permissions +5. ✓ Enable BlueZ experimental mode (required for proper BLE connectivity) +6. ✓ 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): +```bash +./install.sh --skip-experimental +``` ### Option B: Manual Installation @@ -100,7 +108,35 @@ mkdir -p ~/.reticulum/interfaces cp src/RNS/Interfaces/BLE*.py ~/.reticulum/interfaces/ ``` -#### 4. Grant Bluetooth Permissions +#### 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): +```bash +sudo systemctl edit bluetooth +``` + +Add these lines: +``` +[Service] +ExecStart= +ExecStart=/usr/lib/bluetooth/bluetoothd -E +``` + +Save and restart Bluetooth: +```bash +sudo systemctl daemon-reload +sudo systemctl restart bluetooth +``` + +Verify it's enabled: +```bash +ps aux | grep bluetoothd +# Should show: /usr/lib/bluetooth/bluetoothd -E +``` + +#### 5. Grant Bluetooth Permissions For non-root operation: ```bash @@ -199,9 +235,21 @@ python ble_minimal_test.py test - Set `enable_peripheral = no` to disable peripheral mode ### Permission denied errors -- Grant capabilities to Python (see Installation → Manual Installation → step 4) +- 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: diff --git a/examples/config_example.toml b/examples/config_example.toml index f8482b9..823fd75 100644 --- a/examples/config_example.toml +++ b/examples/config_example.toml @@ -253,6 +253,19 @@ power_mode = balanced # - Restart Bluetooth service (Linux: sudo systemctl restart bluetooth) # - Check device_name is not too long (max ~20 characters) # +# 6. BR/EDR connection errors (br-connection-profile-unavailable, ProfileUnavailable): +# IMPORTANT: This is the most common BLE connection issue! +# - Symptoms: Devices connect then immediately disconnect, "ConnectDevice() unavailable" in logs +# - Cause: BlueZ attempting Classic Bluetooth (BR/EDR) instead of BLE (LE) connections +# - Solution: Enable BlueZ experimental mode (required for proper BLE connectivity) +# Linux: sudo systemctl edit bluetooth +# Add: [Service] +# ExecStart= +# ExecStart=/usr/lib/bluetooth/bluetoothd -E +# Then: sudo systemctl daemon-reload && sudo systemctl restart bluetooth +# - If you used install.sh, it should have enabled this automatically +# - Verify: ps aux | grep bluetoothd (should show -E flag) +# # For more troubleshooting, see README.md # ============================================================================ diff --git a/install.sh b/install.sh index 0db1189..aa6f9a6 100755 --- a/install.sh +++ b/install.sh @@ -51,19 +51,26 @@ pip_install() { # Parse command line arguments CUSTOM_CONFIG_DIR="" +SKIP_BLUEZ_EXPERIMENTAL=false while [[ $# -gt 0 ]]; do case $1 in --config) CUSTOM_CONFIG_DIR="$2" shift 2 ;; + --skip-experimental) + SKIP_BLUEZ_EXPERIMENTAL=true + shift + ;; -h|--help) - echo "Usage: $0 [--config CONFIG_DIR]" + echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" - echo " --config CONFIG_DIR Install to custom Reticulum config directory" - echo " (default: ~/.reticulum)" - echo " -h, --help Show this help message" + echo " --config CONFIG_DIR Install to custom Reticulum config directory" + echo " (default: ~/.reticulum)" + echo " --skip-experimental Skip enabling BlueZ experimental mode" + echo " WARNING: May cause BLE connection failures" + echo " -h, --help Show this help message" exit 0 ;; *) @@ -351,6 +358,139 @@ fi echo +# Step 5A: BlueZ Experimental Mode +print_header "BlueZ Experimental Mode" + +# Check if bluetoothctl is available +if ! command -v bluetoothctl &> /dev/null; then + print_warning "bluetoothctl not found - BlueZ may not be installed" + print_info "BLE interface requires BlueZ for Bluetooth functionality" + echo +elif ! command -v systemctl &> /dev/null; then + print_warning "systemctl not found - cannot configure BlueZ experimental mode" + print_info "This system may not use systemd, or this may be a container environment" + echo +else + # Detect BlueZ version + BLUEZ_VERSION=$(bluetoothctl --version 2>/dev/null | grep -oP '\d+\.\d+' | head -1) + + if [ -z "$BLUEZ_VERSION" ]; then + print_warning "Could not detect BlueZ version" + echo + else + print_info "Detected BlueZ version: $BLUEZ_VERSION" + + # Parse version to check if >= 5.49 + VERSION_MAJOR=$(echo "$BLUEZ_VERSION" | cut -d. -f1) + VERSION_MINOR=$(echo "$BLUEZ_VERSION" | cut -d. -f2) + + if [ "$VERSION_MAJOR" -lt 5 ] || ([ "$VERSION_MAJOR" -eq 5 ] && [ "$VERSION_MINOR" -lt 49 ]); then + print_warning "BlueZ version $BLUEZ_VERSION does not support experimental mode (requires >= 5.49)" + print_info "BLE interface will work with standard connection methods" + print_info "Consider upgrading BlueZ for full BLE compatibility" + echo + else + # Check if experimental mode is already enabled + if systemctl status bluetooth 2>/dev/null | grep -q -- "-E\|--experimental"; then + print_success "BlueZ experimental mode already enabled" + echo + elif [ "$SKIP_BLUEZ_EXPERIMENTAL" = true ]; then + # User explicitly skipped experimental mode - show strong warning + echo + print_error "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_error "WARNING: Skipping BlueZ experimental mode" + print_error "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo + echo -e "${RED}BLE connections may fail with errors like:${NC}" + echo " • br-connection-profile-unavailable" + echo " • ProfileUnavailable" + echo " • Immediate disconnections after pairing" + echo + echo -e "${RED}Your BLE interface may attempt Classic Bluetooth (BR/EDR)${NC}" + echo -e "${RED}connections instead of BLE (LE) connections.${NC}" + echo + echo -e "${YELLOW}This is NOT RECOMMENDED unless you have a specific reason.${NC}" + echo + echo "To enable experimental mode later:" + echo " 1. sudo systemctl edit bluetooth" + echo " 2. Add these lines:" + echo " [Service]" + echo " ExecStart=" + echo " ExecStart=/usr/lib/bluetooth/bluetoothd -E" + echo " 3. sudo systemctl daemon-reload" + echo " 4. sudo systemctl restart bluetooth" + echo + print_error "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo + else + # Enable experimental mode by default + print_info "Enabling BlueZ experimental mode (required for proper BLE connectivity)" + print_info "This enables LE-specific connection methods (ConnectDevice API)" + echo + + # Find bluetoothd path + BLUETOOTHD_PATH="" + for path in /usr/lib/bluetooth/bluetoothd /usr/libexec/bluetooth/bluetoothd; do + if [ -f "$path" ]; then + BLUETOOTHD_PATH="$path" + break + fi + done + + if [ -z "$BLUETOOTHD_PATH" ]; then + print_error "Could not find bluetoothd binary" + print_warning "Tried: /usr/lib/bluetooth/bluetoothd, /usr/libexec/bluetooth/bluetoothd" + echo + else + print_info "Using bluetoothd at: $BLUETOOTHD_PATH" + + # Create systemd override + print_info "Creating systemd override for bluetooth service..." + + # Use sudo only if not running as root + if [ "$EUID" -eq 0 ]; then + # Running as root - no sudo needed + mkdir -p /etc/systemd/system/bluetooth.service.d + cat > /etc/systemd/system/bluetooth.service.d/override.conf < /dev/null < /dev/null && command -v bluetoothctl &> /dev/null; then + # systemctl is available - check if experimental mode was configured + if [ -f /etc/systemd/system/bluetooth.service.d/override.conf ]; then + echo " ✓ Systemd override file created" + if grep -q -- "-E" /etc/systemd/system/bluetooth.service.d/override.conf; then + echo " ✓ Experimental mode flag (-E) configured" + else + echo " ⚠ WARNING: Override file exists but -E flag not found" + fi + else + # No override file - may have been already enabled or not supported + if systemctl status bluetooth 2>/dev/null | grep -q -- "-E\|--experimental"; then + echo " ✓ Experimental mode already enabled (not via installer)" + else + echo " ⚠ WARNING: Experimental mode not configured" + fi + fi +else + # systemctl or bluetoothctl not available (container environment) + echo " ℹ Systemd/BlueZ not available (container environment - OK)" +fi + +echo "" + +# Test --skip-experimental flag +echo "Testing --skip-experimental flag..." +cd "$(dirname "$0")/.." +# Run with --skip-experimental to verify it doesn't fail +./install.sh --config /tmp/test-config-skip --skip-experimental > /tmp/skip-test.log 2>&1 < Date: Tue, 28 Oct 2025 23:38:27 -0400 Subject: [PATCH 2/6] fix: improve RNS installation verification for user-local pip installs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pip installs RNS to ~/.local/bin (user installation), the rnsd command is not immediately available in PATH, causing the installer to incorrectly report "Reticulum installation failed" even though installation succeeded. Changes: - Add ~/.local/bin to PATH at the start of Reticulum check - Add ~/.local/bin to PATH after pip install rns - Check multiple locations for rnsd command: 1. In PATH (command -v rnsd) 2. In ~/.local/bin directly 3. As Python package (python3 -c "import RNS") - Make rnsd executable if found in ~/.local/bin - Add PATH configuration instructions in final setup steps - Dynamic step numbering based on whether PATH note is needed This fixes false installation failures on Raspberry Pi OS and other systems where pip defaults to user-local installation. Tested on: Raspberry Pi Zero 2 W with Raspberry Pi OS Lite 64-bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- install.sh | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index aa6f9a6..3a596cc 100755 --- a/install.sh +++ b/install.sh @@ -158,6 +158,11 @@ RNS_VENV="" RNS_PYTHON="" INSTALL_MODE="" +# Add user's local bin to PATH if it exists (common pip install location) +if [ -d "$HOME/.local/bin" ]; then + export PATH="$HOME/.local/bin:$PATH" +fi + # Check if rnsd is available if command -v rnsd &> /dev/null; then print_success "Found rnsd command" @@ -197,16 +202,33 @@ else # Install Reticulum using our pip helper function pip_install rns - # Verify installation + # Add user's local bin to PATH (pip may install there) + export PATH="$HOME/.local/bin:$PATH" + + # Verify installation (check multiple locations and Python import) if command -v rnsd &> /dev/null; then print_success "Reticulum installed successfully" INSTALL_MODE="system" RNS_PYTHON="python3" + elif [ -f "$HOME/.local/bin/rnsd" ]; then + print_success "Reticulum installed successfully (user installation)" + print_info "rnsd location: $HOME/.local/bin/rnsd" + INSTALL_MODE="system" + RNS_PYTHON="python3" + # Ensure it's executable + chmod +x "$HOME/.local/bin/rnsd" 2>/dev/null || true + elif python3 -c "import RNS" 2>/dev/null; then + print_warning "Reticulum Python package installed, but rnsd command not found in PATH" + print_info "You may need to add ~/.local/bin to your PATH" + echo " Add to ~/.bashrc: export PATH=\"\$HOME/.local/bin:\$PATH\"" + INSTALL_MODE="system" + RNS_PYTHON="python3" else print_error "Reticulum installation failed" echo echo "Please try installing manually:" echo " pip install rns" + echo " # Then add to PATH: export PATH=\"\$HOME/.local/bin:\$PATH\"" echo "Or visit: https://reticulum.network" exit 1 fi @@ -514,14 +536,26 @@ echo " └────────────────────── echo echo "2. See examples/config_example.toml for all configuration options" echo -echo "3. Start Reticulum:" + +# Add PATH note if rnsd is in user's local bin +STEP_NUM=3 +if [ -f "$HOME/.local/bin/rnsd" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then + echo "3. Add ~/.local/bin to your PATH (for rnsd command):" + echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc" + echo " source ~/.bashrc" + echo + STEP_NUM=4 +fi + +echo "$STEP_NUM. Start Reticulum:" if [ -n "$CUSTOM_CONFIG_DIR" ]; then echo " rnsd --config $CONFIG_DIR --verbose" else echo " rnsd --verbose" fi echo -echo "4. Verify the interface is running:" +STEP_NUM=$((STEP_NUM + 1)) +echo "$STEP_NUM. Verify the interface is running:" echo " rnstatus" echo From c6393994e4703c6dace55b1755addd353dbdf602 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Tue, 28 Oct 2025 23:43:39 -0400 Subject: [PATCH 3/6] fix: add libcap2-bin/libcap dependency for setcap command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setcap command (used to grant Bluetooth capabilities to Python) requires the libcap2-bin package on Debian/Ubuntu or libcap on Arch. Fresh Raspberry Pi OS Lite installations don't include this by default, causing "Invalid file 'setcap' for capability operation" errors. Changes: - Added libcap2-bin to Debian/Ubuntu/Raspberry Pi OS dependencies - Added libcap to Arch Linux dependencies - Added setcap availability check before Bluetooth permissions step - Auto-install libcap2-bin/libcap if setcap is not found - Improved error handling with clear error messages - Verify setcap command succeeded before showing success This ensures setcap is available before attempting to grant capabilities, preventing installation failures on minimal OS installations. Fixes error encountered on: Raspberry Pi Zero 2 W with Raspberry Pi OS Lite 64-bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- install.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/install.sh b/install.sh index 3a596cc..2bc514f 100755 --- a/install.sh +++ b/install.sh @@ -242,20 +242,20 @@ print_header "Installing System Dependencies" if command -v apt-get &> /dev/null; then # Debian/Ubuntu/Raspberry Pi OS print_info "Detected Debian/Ubuntu-based system" - echo "Installing: python3-pip python3-gi python3-dbus python3-cairo bluez" + echo "Installing: python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin" # Use sudo only if not running as root if [ "$EUID" -eq 0 ]; then apt-get update - apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez + apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin else sudo apt-get update - sudo apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez + sudo apt-get install -y python3-pip python3-gi python3-dbus python3-cairo bluez libcap2-bin fi print_success "System dependencies installed (using pre-compiled system packages)" elif command -v pacman &> /dev/null; then # Arch Linux print_info "Detected Arch Linux" - echo "Installing: base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils" + echo "Installing: base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap" print_warning "Note: PyGObject will be compiled from pip due to version requirements (bluezero needs <3.52.0, Arch has 3.54.5)" # Use sudo only if not running as root if [ "$EUID" -eq 0 ]; then @@ -263,10 +263,10 @@ elif command -v pacman &> /dev/null; then pacman -Sy --noconfirm # Skip python-gobject to avoid version conflict - pip will compile PyGObject # gobject-introspection provides dev files needed for PyGObject compilation - pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils + pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap else sudo pacman -Sy --noconfirm - sudo pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils + sudo pacman -S --needed --noconfirm base-devel gobject-introspection python-pip python-dbus python-cairo bluez bluez-utils libcap fi print_success "System dependencies installed (PyGObject will be compiled from pip)" else @@ -361,6 +361,40 @@ print_header "Bluetooth Permissions" print_info "For BLE to work without root, Python needs network capabilities" echo +# Check if setcap is available +if ! command -v setcap &> /dev/null; then + print_error "setcap command not found" + print_info "Installing libcap2-bin package..." + + if command -v apt-get &> /dev/null; then + if [ "$EUID" -eq 0 ]; then + apt-get install -y libcap2-bin + else + sudo apt-get install -y libcap2-bin + fi + elif command -v pacman &> /dev/null; then + if [ "$EUID" -eq 0 ]; then + pacman -S --needed --noconfirm libcap + else + sudo pacman -S --needed --noconfirm libcap + fi + else + print_error "Could not install libcap2-bin/libcap automatically" + print_warning "Please install manually and re-run the installer" + echo + fi + + # Verify setcap is now available + if ! command -v setcap &> /dev/null; then + print_error "setcap still not available after installation attempt" + print_warning "You will need to run rnsd with sudo, or manually install libcap2-bin" + echo + else + print_success "setcap installed successfully" + echo + fi +fi + PYTHON_PATH=$(which python3) echo "The following command will grant capabilities to Python:" @@ -370,8 +404,18 @@ echo read -p "Grant Bluetooth permissions now? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then - sudo setcap 'cap_net_raw,cap_net_admin+eip' "$PYTHON_PATH" - print_success "Bluetooth permissions granted" + if command -v setcap &> /dev/null; then + sudo setcap 'cap_net_raw,cap_net_admin+eip' "$PYTHON_PATH" + if [ $? -eq 0 ]; then + print_success "Bluetooth permissions granted" + else + print_error "Failed to grant Bluetooth permissions" + print_warning "You may need to run rnsd with sudo" + fi + else + print_error "setcap command not available, cannot grant permissions" + print_warning "You will need to run rnsd with sudo" + fi else print_warning "Skipped. You may need to run rnsd with sudo" echo " To grant permissions later, run:" From 7cd0244e5a2e58c8dfcfaba6ab25c225943adbcd Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Tue, 28 Oct 2025 23:51:15 -0400 Subject: [PATCH 4/6] fix: resolve Python symlinks and make Bluetooth permissions automatic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setcap command fails on symlinks with "Invalid file 'setcap' for capability operation". On many systems (including Raspberry Pi OS), /usr/bin/python3 is a symlink to the versioned binary (e.g., /usr/bin/python3.13). The interactive prompt also required manual intervention during installation. Changes: - Automatically grant Bluetooth permissions (removed y/N prompt) - Detect if python3 is a symlink and resolve to actual binary using readlink -f - Verify resolved path is valid before applying setcap - Use getcap to verify capabilities were actually set - Added --skip-bt-permissions flag for users who want to skip this step - Improved error messages with specific troubleshooting steps - Show detected and resolved Python paths for transparency This makes installation fully automated while handling the symlink issue that was causing setcap failures on Raspberry Pi OS and other Debian-based systems. Fixes: "Invalid file 'setcap' for capability operation" error Tested on: Raspberry Pi Zero 2 W with Raspberry Pi OS Lite 64-bit (Debian Trixie) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- install.sh | 152 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 54 deletions(-) diff --git a/install.sh b/install.sh index 2bc514f..914864b 100755 --- a/install.sh +++ b/install.sh @@ -52,6 +52,7 @@ pip_install() { # Parse command line arguments CUSTOM_CONFIG_DIR="" SKIP_BLUEZ_EXPERIMENTAL=false +SKIP_BT_PERMISSIONS=false while [[ $# -gt 0 ]]; do case $1 in --config) @@ -62,6 +63,10 @@ while [[ $# -gt 0 ]]; do SKIP_BLUEZ_EXPERIMENTAL=true shift ;; + --skip-bt-permissions) + SKIP_BT_PERMISSIONS=true + shift + ;; -h|--help) echo "Usage: $0 [OPTIONS]" echo "" @@ -70,6 +75,8 @@ while [[ $# -gt 0 ]]; do echo " (default: ~/.reticulum)" echo " --skip-experimental Skip enabling BlueZ experimental mode" echo " WARNING: May cause BLE connection failures" + echo " --skip-bt-permissions Skip granting Bluetooth permissions" + echo " (you will need to run rnsd with sudo)" echo " -h, --help Show this help message" exit 0 ;; @@ -358,71 +365,108 @@ echo # Step 5: Bluetooth permissions print_header "Bluetooth Permissions" -print_info "For BLE to work without root, Python needs network capabilities" -echo +# Check if user wants to skip Bluetooth permissions +if [ "$SKIP_BT_PERMISSIONS" = true ]; then + print_warning "Skipping Bluetooth permissions (--skip-bt-permissions flag)" + print_info "You will need to run rnsd with sudo, or grant permissions manually:" + echo " sudo setcap 'cap_net_raw,cap_net_admin+eip' \$(readlink -f \$(which python3))" + echo +else + print_info "For BLE to work without root, Python needs network capabilities" + print_info "Automatically granting capabilities to Python..." + echo -# Check if setcap is available -if ! command -v setcap &> /dev/null; then - print_error "setcap command not found" - print_info "Installing libcap2-bin package..." - - if command -v apt-get &> /dev/null; then - if [ "$EUID" -eq 0 ]; then - apt-get install -y libcap2-bin - else - sudo apt-get install -y libcap2-bin - fi - elif command -v pacman &> /dev/null; then - if [ "$EUID" -eq 0 ]; then - pacman -S --needed --noconfirm libcap - else - sudo pacman -S --needed --noconfirm libcap - fi - else - print_error "Could not install libcap2-bin/libcap automatically" - print_warning "Please install manually and re-run the installer" - echo - fi - - # Verify setcap is now available + # Check if setcap is available if ! command -v setcap &> /dev/null; then - print_error "setcap still not available after installation attempt" - print_warning "You will need to run rnsd with sudo, or manually install libcap2-bin" - echo - else - print_success "setcap installed successfully" - echo - fi -fi + print_error "setcap command not found" + print_info "Installing libcap2-bin package..." -PYTHON_PATH=$(which python3) - -echo "The following command will grant capabilities to Python:" -echo " sudo setcap 'cap_net_raw,cap_net_admin+eip' $PYTHON_PATH" -echo - -read -p "Grant Bluetooth permissions now? (y/N) " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - if command -v setcap &> /dev/null; then - sudo setcap 'cap_net_raw,cap_net_admin+eip' "$PYTHON_PATH" - if [ $? -eq 0 ]; then - print_success "Bluetooth permissions granted" + if command -v apt-get &> /dev/null; then + if [ "$EUID" -eq 0 ]; then + apt-get install -y libcap2-bin + else + sudo apt-get install -y libcap2-bin + fi + elif command -v pacman &> /dev/null; then + if [ "$EUID" -eq 0 ]; then + pacman -S --needed --noconfirm libcap + else + sudo pacman -S --needed --noconfirm libcap + fi else - print_error "Failed to grant Bluetooth permissions" + print_error "Could not install libcap2-bin/libcap automatically" + print_warning "Please install manually and re-run the installer" + echo + fi + + # Verify setcap is now available + if ! command -v setcap &> /dev/null; then + print_error "setcap still not available after installation attempt" + print_warning "You will need to run rnsd with sudo, or manually install libcap2-bin" + echo + else + print_success "setcap installed successfully" + echo + fi + fi + + if command -v setcap &> /dev/null; then + # Get python3 path + PYTHON_PATH=$(which python3) + print_info "Detected Python at: $PYTHON_PATH" + + # Check if it's a symlink and resolve it + if [ -L "$PYTHON_PATH" ]; then + print_warning "Python3 is a symlink (setcap requires the actual binary)" + PYTHON_REAL=$(readlink -f "$PYTHON_PATH") + print_info "Resolved to actual binary: $PYTHON_REAL" + + # Verify the resolved path exists and is a file + if [ ! -f "$PYTHON_REAL" ]; then + print_error "Could not resolve Python binary: $PYTHON_REAL" + print_warning "You may need to run rnsd with sudo" + echo + elif [ -L "$PYTHON_REAL" ]; then + print_error "Python path is still a symlink after resolution" + print_warning "Manual intervention required - you may need to run rnsd with sudo" + echo + else + PYTHON_PATH="$PYTHON_REAL" + fi + fi + + # Grant capabilities if we have a valid path + if [ -f "$PYTHON_PATH" ] && [ ! -L "$PYTHON_PATH" ]; then + print_info "Granting capabilities to: $PYTHON_PATH" + sudo setcap 'cap_net_raw,cap_net_admin+eip' "$PYTHON_PATH" + + if [ $? -eq 0 ]; then + print_success "Bluetooth permissions granted successfully" + # Verify capabilities were actually set + if command -v getcap &> /dev/null; then + CAPS=$(getcap "$PYTHON_PATH" 2>/dev/null) + if [ -n "$CAPS" ]; then + print_info "Verified: $CAPS" + fi + fi + else + print_error "Failed to grant Bluetooth permissions" + print_warning "You may need to run rnsd with sudo" + echo + print_info "To grant permissions manually, run:" + echo " sudo setcap 'cap_net_raw,cap_net_admin+eip' $PYTHON_PATH" + fi + else + print_error "Could not determine valid Python binary path" print_warning "You may need to run rnsd with sudo" fi else print_error "setcap command not available, cannot grant permissions" print_warning "You will need to run rnsd with sudo" fi -else - print_warning "Skipped. You may need to run rnsd with sudo" - echo " To grant permissions later, run:" - echo " sudo setcap 'cap_net_raw,cap_net_admin+eip' \$(which python3)" -fi -echo + echo +fi # Step 5A: BlueZ Experimental Mode print_header "BlueZ Experimental Mode" From 21c8082dff7fa572131a1e9f618ef8f5e1528da5 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Tue, 28 Oct 2025 23:58:41 -0400 Subject: [PATCH 5/6] feat: automatically add ~/.local/bin to PATH when RNS installed there MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pip installs RNS to ~/.local/bin (user-local installation), the rnsd command is not immediately available because ~/.local/bin is not in PATH. This required users to manually add it to their .bashrc. Changes: - Automatically add ~/.local/bin to PATH in .bashrc after RNS user installation - Check if .local/bin is already in .bashrc before adding (avoid duplicates) - Show clear message about reloading shell: "source ~/.bashrc" - Update final "Next steps" to conditionally show PATH setup - Only show manual PATH instructions if auto-add didn't happen This makes installation fully automated - users can run rnsd immediately after reloading their shell, without manual PATH configuration. User experience: ✓ Reticulum installed successfully (user installation) ℹ rnsd location: /home/user/.local/bin/rnsd ℹ Adding ~/.local/bin to PATH in ~/.bashrc... ✓ Added ~/.local/bin to PATH in ~/.bashrc ⚠ Reload your shell to use rnsd command: source ~/.bashrc # Or open a new terminal 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- install.sh | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/install.sh b/install.sh index 914864b..0bd51f0 100755 --- a/install.sh +++ b/install.sh @@ -224,6 +224,23 @@ else RNS_PYTHON="python3" # Ensure it's executable chmod +x "$HOME/.local/bin/rnsd" 2>/dev/null || true + + # Automatically add ~/.local/bin to PATH if not already there + if [ -f "$HOME/.bashrc" ]; then + if ! grep -q '.local/bin' "$HOME/.bashrc" 2>/dev/null; then + print_info "Adding ~/.local/bin to PATH in ~/.bashrc..." + echo '' >> "$HOME/.bashrc" + echo '# Added by Reticulum BLE installer' >> "$HOME/.bashrc" + echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc" + print_success "Added ~/.local/bin to PATH in ~/.bashrc" + print_warning "Reload your shell to use rnsd command:" + echo " source ~/.bashrc" + echo " # Or open a new terminal" + echo + else + print_info "~/.local/bin already in PATH configuration" + fi + fi elif python3 -c "import RNS" 2>/dev/null; then print_warning "Reticulum Python package installed, but rnsd command not found in PATH" print_info "You may need to add ~/.local/bin to your PATH" @@ -625,14 +642,17 @@ echo echo "2. See examples/config_example.toml for all configuration options" echo -# Add PATH note if rnsd is in user's local bin +# Add PATH note only if rnsd is in user's local bin AND not added to .bashrc STEP_NUM=3 -if [ -f "$HOME/.local/bin/rnsd" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then - echo "3. Add ~/.local/bin to your PATH (for rnsd command):" - echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc" - echo " source ~/.bashrc" - echo - STEP_NUM=4 +if [ -f "$HOME/.local/bin/rnsd" ] && [ -f "$HOME/.bashrc" ]; then + # Only show if we didn't automatically add it (i.e., it wasn't already there) + if ! grep -q '.local/bin' "$HOME/.bashrc" 2>/dev/null; then + echo "3. Add ~/.local/bin to your PATH (for rnsd command):" + echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc" + echo " source ~/.bashrc" + echo + STEP_NUM=4 + fi fi echo "$STEP_NUM. Start Reticulum:" From e7ee42ddc50c6b47309fc6ca9ca89d2c7c48a0ca Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Wed, 29 Oct 2025 00:02:11 -0400 Subject: [PATCH 6/6] refactor: remove box border from config example for easier copy-paste MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fancy box border (┌─┐│└┘) around the configuration example made it difficult to copy-paste into the config file. Users had to manually remove the vertical line characters from each line. Changes: - Removed box border characters (┌, ─, ┐, │, └, ┘) - Kept the same indentation and formatting - Added "(copy-paste ready)" note to clarify it can be directly pasted - Maintains visual structure with proper spacing The configuration example is now directly copy-pasteable into the Reticulum config file without any manual editing required. Before: ┌─────────────────────────────────────────┐ │ [[BLE Interface]] │ │ type = BLEInterface │ ... After: [[BLE Interface]] type = BLEInterface enabled = yes ... 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- install.sh | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/install.sh b/install.sh index 0bd51f0..f3a3520 100755 --- a/install.sh +++ b/install.sh @@ -628,16 +628,15 @@ echo echo "1. Add the BLE interface to your Reticulum config:" echo " File: $CONFIG_FILE" echo -echo " Add this section:" -echo " ┌─────────────────────────────────────────┐" -echo " │ [[BLE Interface]] │" -echo " │ type = BLEInterface │" -echo " │ enabled = yes │" -echo " │ │" -echo " │ # Enable both modes for mesh │" -echo " │ enable_peripheral = yes │" -echo " │ enable_central = yes │" -echo " └─────────────────────────────────────────┘" +echo " Add this section (copy-paste ready):" +echo +echo " [[BLE Interface]]" +echo " type = BLEInterface" +echo " enabled = yes" +echo +echo " # Enable both modes for mesh" +echo " enable_peripheral = yes" +echo " enable_central = yes" echo echo "2. See examples/config_example.toml for all configuration options" echo