If you are trying to config wifi raspberry pi boards running the modern Bookworm OS (or later), stop looking for /etc/wpa_supplicant/wpa_supplicant.conf. That legacy file is ignored. Raspberry Pi OS has transitioned entirely to NetworkManager and nmcli for wireless configuration. This guide gives you the exact terminal commands, a hardware-backed Python monitoring script, and the specific debugging steps to fix the exact error strings NetworkManager throws when connections fail.

Target Board Variant: This guide and code specifically target the Raspberry Pi 5 (8GB) and Raspberry Pi 4 Model B running Raspberry Pi OS Bookworm (64-bit). The Python script relies on gpiozero with the lgpio backend, which is natively supported on Pi 5.

Parts List & Hardware Pin Mapping

To make WiFi debugging physical, we are building a status indicator with a hardware fallback trigger. If the Pi drops off the network, the LED turns red. Pressing the button forces a connection to a mobile hotspot fallback.

Component Specification / Variant GPIO Pin (BCM) Physical Pin
Raspberry Pi Pi 5 (8GB) or Pi 4 Model B N/A N/A
RGB LED (Common Cathode) 5mm standard, 20mA 17 (R), 27 (G), 22 (B) 11, 13, 15
Current Limiting Resistors 3x 220Ω or 330Ω (1/4W) In-line with R, G, B N/A
Tactile Pushbutton 6x6mm SPST Normally Open 5 (Input) 29
Power & Ground N/A 3.3V (Pwr), GND 1 (3.3V), 6 (GND)

The Modern CLI Method: nmcli Step-by-Step

NetworkManager replaces both wpa_supplicant and dhcpcd. Here is the exact sequence to scan, connect, and verify your wireless connection from the terminal.

  1. Check the Radio State: Before scanning, ensure the WiFi radio isn't soft-blocked by regulatory domain rules.
    nmcli radio wifi
    If it returns 'disabled', enable it with: nmcli radio wifi on
  2. Scan for Networks: List available SSIDs with signal strength.
    nmcli device wifi list
  3. Connect to the SSID: Pass your credentials directly. NetworkManager will automatically save this as a persistent profile.
    sudo nmcli device wifi connect "Your_SSID_Name" password "Your_Secure_Password"
  4. Verify the Connection Profile: Confirm the profile is set to auto-connect on boot.
    nmcli connection show
    Look for your SSID in the 'NAME' column and ensure 'AUTOCONNECT' is set to 'yes'.
Callout Tip: The WLAN Country Code Gotcha
If nmcli device wifi list returns nothing, or connections instantly drop, your regulatory domain is likely unset. The Pi disables WiFi transmission until a country code is defined. Run sudo raspi-config, navigate to Localisation Options > WLAN Country, select your region, and reboot.

Python WiFi Monitor & Fallback Script

This script monitors the NetworkManager state. If the primary WiFi drops, it illuminates the red LED and attempts a reconnection. If you press the physical button on GPIO 5, it forces a connection to a fallback mobile hotspot. This is highly useful for headless Pi deployments in the field.

import subprocess
import time
from gpiozero import RGBLED, Button
from signal import pause

# --- Pin Definitions (BCM Numbering) ---
RED_PIN = 17
GREEN_PIN = 27
BLUE_PIN = 22
BUTTON_PIN = 5

# Initialize Hardware
led = RGBLED(red=RED_PIN, green=GREEN_PIN, blue=BLUE_PIN)
btn = Button(BUTTON_PIN, pull_up=True, bounce_time=0.1)

# --- Network Configuration ---
PRIMARY_SSID = "HomeNetwork_5G"
FALLBACK_SSID = "FieldMobileHotspot"
WIFI_PASS = "YourSecurePasswordHere"

def check_wifi_status():
    """Queries NetworkManager for active connection state."""
    try:
        result = subprocess.run(
            ["nmcli", "-t", "-f", "STATE", "general", "status"],
            capture_output=True, text=True, check=True
        )
        return "connected" in result.stdout.lower()
    except subprocess.CalledProcessError:
        return False

def attempt_connect(ssid):
    """Attempts to connect to a specific SSID using nmcli."""
    led.color = (1, 0.5, 0)  # Orange indicates 'connecting'
    try:
        subprocess.run(
            ["sudo", "nmcli", "device", "wifi", "connect", ssid, "password", WIFI_PASS],
            check=True, capture_output=True, text=True
        )
        return True
    except subprocess.CalledProcessError as e:
        print(f"Connection failed for {ssid}: {e.stderr.strip()}")
        return False

def fallback_trigger():
    """Hardware button callback to force fallback network."""
    print("Button pressed! Attempting fallback connection...")
    if not attempt_connect(FALLBACK_SSID):
        led.color = (1, 0, 0)  # Solid red on failure

# Bind button press event
btn.when_pressed = fallback_trigger

# --- Main Monitoring Loop ---
try:
    print("Starting WiFi Monitor... Press Ctrl+C to exit.")
    while True:
        if check_wifi_status():
            led.color = (0, 1, 0)  # Green = Connected
        else:
            led.color = (1, 0, 0)  # Red = Disconnected
            print("Network dropped. Attempting primary reconnect...")
            attempt_connect(PRIMARY_SSID)
        
        time.sleep(5)  # Poll every 5 seconds to avoid CPU spam
except KeyboardInterrupt:
    print("\nMonitor stopped.")
    led.off()

How to extend or simplify this build: To simplify, remove the button and fallback SSID logic, leaving only the LED status loop. To extend, integrate the official NetworkManager D-Bus API to listen for asynchronous state change signals rather than polling every 5 seconds, which reduces CPU wakeups on battery-powered Pi projects.

Debugging: Exact Error Strings & Ranked Causes

When configuring WiFi via CLI or Python, NetworkManager will halt and throw specific errors. Here is how to decode them.

Error 1: "Error: Connection activation failed: (7) Secrets were required, but not provided."

What it means: NetworkManager found the SSID, but the PSK (password) is missing, incorrect, or the encryption type (WPA2 vs WPA3) mismatches the saved profile.

  • Cause 1 (Most Likely): Typo in the password string, or passing the password without quotes in bash, causing special characters (like $ or &) to be evaluated as variables.
  • Cause 2: You are trying to connect to a WPA3-Enterprise network using a standard WPA2-Personal command. You must configure 802.1x certificates via nmtui instead.
  • Fix: Delete the corrupted profile and re-enter with strict quoting: nmcli connection delete "SSID" followed by the connect command using single quotes for the password.

Error 2: "Error: No suitable device found for this connection" or "Error: Device wlan0 not found"

What it means: The software stack cannot see the physical WiFi chip.

  • Cause 1 (Most Likely): The wlan0 interface is soft-blocked by rfkill.
  • Cause 2: The brcmfmac firmware crashed or failed to load during boot (common if the power supply is marginal and the Pi 5 brownouts the PCIe/WiFi bus).
  • Cause 3: NetworkManager service is masked or conflicting with legacy dhcpcd services left over from an OS upgrade.
The First 3 Things to Check When WiFi Fails:
  1. RF Kill Status: Run rfkill list. If 'Soft blocked' says 'yes', run sudo rfkill unblock wifi.
  2. Service State: Run systemctl status NetworkManager. Ensure it is 'active (running)'. If you see 'dhcpcd.service' running alongside it, disable the legacy service: sudo systemctl disable dhcpcd.
  3. Power Supply Integrity: Check dmesg | grep -i voltage. If you see 'Under-voltage detected', the WiFi chip is the first peripheral to drop offline. Upgrade to the official 27W USB-C PD power supply.

Frequently Asked Questions

How to config wifi raspberry pi headless without a monitor?

For Bookworm OS, the legacy method of dropping a wpa_supplicant.conf file into the boot partition no longer works. Instead, use the Raspberry Pi Imager on your desktop PC. Click the "Gear" icon (Advanced Options) before flashing the SD card. Here, you can input your SSID, password, and set the WLAN country code. The Imager securely injects these credentials into the NetworkManager configuration during the first boot sequence. Alternatively, if you are using a USB-to-TTL serial console cable, plug it into GPIO 14 (TX) and 15 (RX), connect via PuTTY at 115200 baud, and use the nmcli commands detailed above.

Why is my raspberry pi wifi disconnecting randomly on Bookworm?

Random disconnects on the Pi 4 and Pi 5 are almost always tied to power management or USB 3.0 interference. First, the Pi's WiFi chip attempts to enter power-save mode, which causes latency spikes and drops on some routers. You can disable WiFi power management via NetworkManager by creating a configuration file:
sudo nano /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf
Change the value from 3 (enabled) to 2 (disabled). Save and reboot. Second, if you have a USB 3.0 SSD plugged into the Pi, unshielded USB 3.0 data lines emit RF noise exactly in the 2.4GHz spectrum. Move your Pi to a 5GHz network, or use a shielded USB extension cable to move the SSD away from the Pi's antenna.

How to switch between WiFi networks using Python on Raspberry Pi?

As demonstrated in the script above, you use Python's built-in subprocess module to call nmcli. Because NetworkManager handles the underlying DHCP requests and WPA handshakes, you do not need third-party networking libraries. Simply wrap the command ["nmcli", "device", "wifi", "connect", "SSID", "password", "PASS"] in subprocess.run() with capture_output=True. Always wrap this in a try/except subprocess.CalledProcessError block, as nmcli will return a non-zero exit code if the AP is out of range, allowing your Python script to gracefully trigger a fallback routine rather than crashing the entire application.