diff --git a/README.md b/README.md index 554e0ac..db209ed 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ chmod +x install.sh ``` The script will: -1. ✓ Detect if Reticulum is in a venv or system-wide -2. ✓ Install system dependencies (BlueZ, dbus) -3. ✓ Install Python packages in the correct environment +1. ✓ Detect if Reticulum is in a venv, pipx, or system-wide +2. ✓ Install system dependencies (BlueZ, dbus, build tools if needed) +3. ✓ Install Python packages in the correct environment (via pipx inject if needed) 4. ✓ Copy BLE interface files to `~/.reticulum/interfaces/` (or custom config directory if specified) 5. ✓ Enable BlueZ experimental mode (required for proper BLE connectivity) 6. ✓ Optionally set up Bluetooth permissions @@ -150,6 +150,99 @@ sudo setcap 'cap_net_raw,cap_net_admin+eip' $(which python3) sudo setcap 'cap_net_raw,cap_net_admin+eip' /path/to/venv/bin/python3 ``` +### Option C: pipx Installation (RNS installed via pipx) + +If you installed Reticulum via `pipx install rns`, the BLE interface requires additional setup because pipx creates isolated virtual environments that cannot access system-installed packages. + +**Note:** The automated installation script (Option A: `./install.sh`) now detects and handles pipx installations automatically. The instructions below are for manual installation or troubleshooting. + +#### 1. Install System Dependencies + +**Arch Linux:** +```bash +sudo pacman -S base-devel gobject-introspection python-dbus python-cairo bluez bluez-utils +``` + +**Debian/Ubuntu/Raspberry Pi OS:** +```bash +sudo apt-get update +sudo apt-get install build-essential python3-dev python3-gi python3-dbus python3-cairo bluez libdbus-1-dev +``` + +#### 2. Inject BLE Dependencies into pipx Environment + +Because pipx creates isolated environments, you must inject the BLE dependencies into the RNS environment: + +```bash +# Inject BLE dependencies into pipx RNS environment +pipx inject rns bleak==1.1.1 bluezero dbus-python +``` + +**Note:** This will compile `dbus-python` from source, which requires the system development libraries installed in step 1. + +#### 3. Copy BLE Interface Files + +```bash +# Copy to Reticulum's interface directory +mkdir -p ~/.reticulum/interfaces +cp src/RNS/Interfaces/BLE*.py ~/.reticulum/interfaces/ +``` + +#### 4. Grant Bluetooth Permissions + +Find the Python executable used by pipx for RNS: + +```bash +# Find pipx RNS Python path +PIPX_RNS_PYTHON=$(pipx runpip rns show rns | grep Location | awk '{print $2}' | sed 's/lib\/python.*/bin\/python3/') + +# Grant capabilities +sudo setcap 'cap_net_raw,cap_net_admin+eip' "$PIPX_RNS_PYTHON" +``` + +Alternatively, find the path manually: +```bash +# List pipx environments +ls ~/.local/pipx/venvs/ + +# Grant capabilities to the rns venv Python +sudo setcap 'cap_net_raw,cap_net_admin+eip' ~/.local/pipx/venvs/rns/bin/python3 +``` + +#### 5. Enable BlueZ Experimental Mode + +The BLE interface requires BlueZ experimental features for proper BLE connectivity: + +```bash +# Edit BlueZ service configuration +sudo systemctl edit bluetooth.service +``` + +Add the following content: +```ini +[Service] +ExecStart= +ExecStart=/usr/lib/bluetooth/bluetoothd --experimental +``` + +Then reload and restart: +```bash +sudo systemctl daemon-reload +sudo systemctl restart bluetooth.service + +# Verify experimental mode is enabled +systemctl status bluetooth.service | grep -i experimental +``` + +#### Why pipx Requires Special Handling + +pipx creates isolated virtual environments with `--no-site-packages` to prevent package conflicts. This means: +- System packages like `python-dbus` (installed via apt/pacman) are not accessible +- `dbus-python` must be compiled from source within the pipx environment +- `pipx inject` installs packages directly into RNS's isolated environment + +This isolation is intentional and prevents conflicts, but requires the extra injection step for system-dependent packages like `dbus-python`. + ## Quick Start ### 1. Configure Reticulum @@ -297,6 +390,20 @@ sudo systemctl start bluetooth The automated installer (v1.x+) automatically checks and powers on the Bluetooth adapter during installation. +### pipx: ModuleNotFoundError for dbus, gi, or bluezero +If you installed RNS via pipx and get import errors like `ModuleNotFoundError: No module named 'dbus'`, `No module named 'gi'`, or `No module named 'bluezero'`: + +**Cause:** pipx creates isolated environments that don't access system packages. + +**Solution:** Follow the [pipx installation instructions](#option-c-pipx-installation-rns-installed-via-pipx) to inject the required dependencies: +```bash +pipx inject rns bleak==1.1.1 bluezero dbus-python +``` + +**Verification:** Test if the modules are accessible: +```bash +pipx run rns python3 -c "import dbus, gi, bleak, bluezero; print('All modules found')" +``` ## Architecture The BLE interface consists of four main components: diff --git a/install.sh b/install.sh index f0563ae..bd35b8c 100755 --- a/install.sh +++ b/install.sh @@ -237,6 +237,7 @@ print_header "Checking for Reticulum" RNS_VENV="" RNS_PYTHON="" INSTALL_MODE="" +PIPX_RNS_PATH="" # Add user's local bin to PATH if it exists (common pip install location) if [ -d "$HOME/.local/bin" ]; then @@ -253,8 +254,41 @@ if command -v rnsd &> /dev/null; then if [ -n "$RNS_LOCATION" ]; then print_success "Found RNS Python package at: $RNS_LOCATION" + # Check if it's a pipx installation (most specific, check first) + if [[ "$RNS_LOCATION" == *"/pipx/venvs/"* ]]; then + print_info "RNS appears to be installed via pipx" + + # Verify pipx command is available + if ! command -v pipx &> /dev/null; then + print_error "RNS is in a pipx path, but pipx command not found!" + echo + echo "Please install pipx:" + echo " python3 -m pip install --user pipx" + echo " python3 -m pipx ensurepath" + exit 1 + fi + + # Verify RNS is listed in pipx + if pipx list 2>/dev/null | grep -q "package rns"; then + INSTALL_MODE="pipx" + + # Extract pipx venv path (e.g., ~/.local/pipx/venvs/rns) + PIPX_RNS_PATH=$(echo "$RNS_LOCATION" | grep -oP '^.*?/pipx/venvs/rns') + RNS_PYTHON="$PIPX_RNS_PATH/bin/python3" + + if [ ! -f "$RNS_PYTHON" ]; then + print_error "pipx Python not found at: $RNS_PYTHON" + exit 1 + fi + + print_success "Detected pipx installation at: $PIPX_RNS_PATH" + else + print_error "RNS appears to be in pipx path, but 'pipx list' doesn't show it" + echo "Run 'pipx list' to verify your pipx installations" + exit 1 + fi # Check if it's in a virtual environment - if [[ "$RNS_LOCATION" == *"/venv/"* ]] || [[ "$RNS_LOCATION" == *"/env/"* ]] || [[ "$VIRTUAL_ENV" != "" ]]; then + elif [[ "$RNS_LOCATION" == *"/venv/"* ]] || [[ "$RNS_LOCATION" == *"/env/"* ]] || [[ "$VIRTUAL_ENV" != "" ]]; then # RNS is in a venv if [ -n "$VIRTUAL_ENV" ]; then RNS_VENV="$VIRTUAL_ENV" @@ -365,9 +399,47 @@ if [[ "$ARCH" == "armhf" ]] || [[ "$(uname -m)" =~ ^(armv6l|armv7l)$ ]]; then fi fi -print_info "Installing pip packages (PyGObject, dbus-python, pycairo provided by system packages)" +if [ "$INSTALL_MODE" = "pipx" ]; then + print_info "Installing dependencies via pipx inject..." + print_warning "dbus-python will be compiled from source (may take 2-3 minutes)" + echo -if [ "$INSTALL_MODE" = "venv" ]; then + # Define dependencies (must match requirements.txt) + DEPS=("bleak==1.1.1" "bluezero" "dbus-python") + + # Inject each dependency individually + for dep in "${DEPS[@]}"; do + print_info "Injecting $dep into RNS environment..." + + if pipx inject rns "$dep"; then + print_success "Injected $dep" + else + print_error "Failed to inject $dep" + echo + echo "Common causes:" + echo " - Missing system build dependencies (see above)" + echo " - Network connectivity issues" + echo + echo "Try manually:" + echo " pipx inject rns $dep --verbose" + exit 1 + fi + echo + done + + # Verify all modules can be imported + print_info "Verifying dependencies..." + if "$RNS_PYTHON" -c "import bleak, bluezero, dbus" 2>/dev/null; then + print_success "All dependencies verified and working" + else + print_error "Dependency verification failed" + echo + echo "Test imports manually:" + echo " $RNS_PYTHON -c 'import bleak, bluezero, dbus'" + exit 1 + fi + +elif [ "$INSTALL_MODE" = "venv" ]; then print_info "Installing to virtual environment: $RNS_VENV" if [ ! -f "$RNS_PYTHON" ]; then @@ -494,9 +566,17 @@ else print_info "Running as root - skipping capability grant (not needed)" print_info "Root user already has all required Bluetooth permissions" elif command -v setcap &> /dev/null; then - # Get python3 path - PYTHON_PATH=$(which python3) - print_info "Detected Python at: $PYTHON_PATH" + # Determine correct Python path based on installation mode + if [ "$INSTALL_MODE" = "pipx" ]; then + PYTHON_PATH="$PIPX_RNS_PATH/bin/python3" + print_info "Using pipx Python: $PYTHON_PATH" + elif [ "$INSTALL_MODE" = "venv" ]; then + PYTHON_PATH="$RNS_VENV/bin/python3" + print_info "Using venv Python: $PYTHON_PATH" + else + PYTHON_PATH=$(which python3) + print_info "Using system Python: $PYTHON_PATH" + fi # Check if it's a symlink and resolve it if [ -L "$PYTHON_PATH" ]; then