The Direct Answer: Does a Raspberry Pi 3 Have Wi-Fi?
Yes, the Raspberry Pi 3 has built-in Wi-Fi, but the exact capabilities depend entirely on which sub-variant you have on your bench. The original Raspberry Pi 3 Model B (released in 2016) features a single-band 802.11n (2.4 GHz only) Wi-Fi chip. The later Raspberry Pi 3 Model B+ (released in 2018) upgraded to a dual-band 802.11ac chip supporting both 2.4 GHz and 5 GHz networks. The lesser-known Raspberry Pi 3 Model A+ also includes the dual-band 5 GHz upgrade.
If you are pulling a Pi 3 out of a drawer for an IoT project in 2026, identifying your exact board is step one. The Wi-Fi chip on the 3B is the Cypress CYW43438, while the 3B+ and 3A+ use the Cypress CYW43455. This isn't just a trivia detail; the 3B's 2.4 GHz-only radio is highly susceptible to interference from USB 3.0 peripherals and microwaves, whereas the 3B+ can escape to the 5 GHz band.
Raspberry Pi 3 Wi-Fi Specification Matrix
| Board Variant | Wi-Fi Chip | Bands | Max Theoretical Speed | Bluetooth |
|---|---|---|---|---|
| Pi 3 Model B | Cypress CYW43438 | 2.4 GHz only (802.11n) | 150 Mbps | 4.1 |
| Pi 3 Model B+ | Cypress CYW43455 | 2.4 GHz & 5 GHz (802.11ac) | 433 Mbps | 4.2 |
| Pi 3 Model A+ | Cypress CYW43455 | 2.4 GHz & 5 GHz (802.11ac) | 433 Mbps | 4.2 |
Decision Tree: Which Board Variant Should You Actually Use?
Don't just default to whatever board you have lying around. Use this decision path to pick the right hardware for your embedded Wi-Fi project.
| Your Project Constraint | If True, Choose... | Why? |
|---|---|---|
| Need to avoid 2.4 GHz RF congestion in an apartment? | Pi 3 Model B+ or 3A+ | 5 GHz support is mandatory for reliable MQTT/HTTP telemetry in crowded RF environments. |
| Running off a 12V battery/solar setup via a buck converter? | Pi 3 Model A+ or Pi Zero 2 W | The Model B+ draws ~500mA+ at idle. The A+ and Zero 2 W drop this to ~200mA, saving your battery bank. |
| Need to plug in a USB webcam or Zigbee dongle? | Pi 3 Model B+ | The A+ only has one USB 2.0 port. The B+ has four. |
| Starting a brand new build from scratch in 2026? | Raspberry Pi Zero 2 W | It uses the same quad-core CPU as the 3B+, has dual-band Wi-Fi, costs ~$15, and sips power. |
Hardware Setup: Pin Mapping and Parts List
For this guide, we are building a Wi-Fi health monitor that reads environmental data and pushes it to an endpoint. We will use the BME280 I2C sensor to justify our GPIO pin mapping.
Parts List
- Compute Module: Raspberry Pi 3 Model B+ (or Zero 2 W with a GPIO header soldered) - Target Board for Code
- Sensor: Adafruit BME280 I2C/SPI Temperature/Humidity/Pressure Sensor (Product ID: 2652) - ~$10.00
- Storage: 16GB SanDisk Extreme microSD (A2 rating for better OS responsiveness) - ~$12.00
- Power: Official Raspberry Pi 5V 2.5A Micro-USB Power Supply. Critical: The Pi 3B+ Wi-Fi chip will randomly drop off the SDIO bus if the 5V rail sags below 4.6V under load.
- Wiring: 4x Female-to-Female silicone jumper wires (26 AWG).
Pin Mapping Table (BCM Numbering)
The Raspberry Pi uses Broadcom (BCM) GPIO numbering in software, which differs from the physical pin numbers on the 40-pin header. Always wire according to the physical layout, but code according to BCM.
| Pi 3 Physical Pin | Pi 3 BCM GPIO | Function | BME280 Sensor Pin |
|---|---|---|---|
| Pin 1 | N/A (Power) | 3.3V DC | VIN (or 3Vo) |
| Pin 6 | N/A (Ground) | Ground | GND |
| Pin 3 | GPIO 2 | I2C SDA1 | SDI / SDA |
| Pin 5 | GPIO 3 | I2C SCL1 | SCK / SCL |
The Code: Wi-Fi Health Monitor and I2C Telemetry
This Python script targets Raspberry Pi OS (Bookworm). It initializes the I2C bus, reads the BME280, verifies the Wi-Fi connection using system calls, and POSTs the payload. It includes robust error handling for both hardware and network failures.
Prerequisites: Run sudo apt update && sudo apt install python3-smbus i2c-tools and pip3 install RPi.bme280 requests.
import time
import subprocess
import smbus2
import bme280
import requests
import json
import sys
# --- PIN & HARDWARE DEFINITIONS ---
# I2C Port 1 maps to BCM GPIO 2 (SDA) and GPIO 3 (SCL)
I2C_PORT = 1
# BME280 default I2C address (check your module, some are 0x77)
BME280_ADDR = 0x76
TELEMETRY_URL = 'https://api.example.com/v1/telemetry'
# Initialize I2C Bus
try:
bus = smbus2.SMBus(I2C_PORT)
# Load calibration parameters from the sensor
calibration_params = bme280.load_calibration_params(bus, BME280_ADDR)
print('[OK] BME280 initialized successfully on I2C bus 1.')
except FileNotFoundError as e:
print(f'[FATAL] I2C bus not found. Is I2C enabled in raspi-config? Error: {e}')
sys.exit(1)
except Exception as e:
print(f'[FATAL] Could not connect to BME280 at address {hex(BME280_ADDR)}. Check wiring. Error: {e}')
sys.exit(1)
def check_wifi_status():
"""Checks if wlan0 is connected and returns the SSID."""
try:
# iwgetid is a lightweight way to check current Wi-Fi association
result = subprocess.run(['iwgetid', '-r'], capture_output=True, text=True, timeout=5)
ssid = result.stdout.strip()
if not ssid:
return False, 'Disconnected'
return True, ssid
except Exception as e:
return False, f'Error: {str(e)}'
def get_sensor_data():
"""Reads environmental data from the BME280."""
try:
data = bme280.sample(bus, BME280_ADDR, calibration_params)
return {
'temp_c': round(data.temperature, 2),
'humidity': round(data.humidity, 2),
'pressure_hpa': round(data.pressure, 2)
}
except Exception as e:
print(f'[WARN] Sensor read failed: {e}')
return None
def main():
print('Starting Wi-Fi Telemetry Node...')
while True:
is_connected, ssid_or_err = check_wifi_status()
if not is_connected:
print(f'[WARN] Wi-Fi not connected. Status: {ssid_or_err}. Retrying in 30s...')
time.sleep(30)
continue
sensor_data = get_sensor_data()
if not sensor_data:
time.sleep(10)
continue
payload = {
'device': 'pi3bplus_node_01',
'ssid': ssid_or_err,
'metrics': sensor_data
}
try:
response = requests.post(TELEMETRY_URL, json=payload, timeout=10)
response.raise_for_status()
print(f'[OK] Pushed to {ssid_or_err}: {json.dumps(sensor_data)}')
except requests.exceptions.ConnectionError as e:
print(f'[ERR] Network unreachable or DNS failure: {e}')
except requests.exceptions.Timeout:
print('[ERR] HTTP Request timed out. Wi-Fi may be associated but routing is dead.')
except Exception as e:
print(f'[ERR] Unexpected HTTP error: {e}')
# Sleep for 5 minutes (300 seconds) between reads
time.sleep(300)
if __name__ == '____main__':
try:
main()
except KeyboardInterrupt:
print('\n[INFO] Script terminated by user.')
sys.exit(0)
Debugging: Network Unreachable and I2C Failures
When your Pi 3 IoT node fails, it usually happens at 2 AM. Here are the exact error strings you will see, ranked by probability, and how to fix them.
First Three Things to Check When It Fails
- Measure the 5V Rail: Use a multimeter on the 5V and GND GPIO pins. If it reads below 4.75V, the Wi-Fi chip will brownout and detach from the SDIO bus. Upgrade your power supply and cable.
- Verify NetworkManager Status: Raspberry Pi OS Bookworm abandoned
wpa_supplicant.conf. If you are trying to configure headless Wi-Fi using the old/etc/wpa_supplicant/method, it will silently fail. You must usenmclior create a NetworkManager connection file in/etc/NetworkManager/system-connections/(Raspberry Pi NetworkManager Docs). - Check I2C Pull-ups: The Pi 3 has internal 1.8kΩ pull-up resistors on the I2C bus, but they are tied to 3.3V. If your BME280 module already has 10kΩ pull-ups, you're fine. If it's a raw chip on a breakout without pull-ups, the bus will float and throw I2C errors.
Exact Error Strings and Ranked Causes
FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'
- Cause 1 (90%): I2C is disabled in the OS. Fix: Run
sudo raspi-config-> Interface Options -> I2C -> Enable. - Cause 2 (10%): You are running the script in a Docker container without passing the
--device /dev/i2c-1flag.
requests.exceptions.ConnectionError: HTTPConnectionPool(host='api.example.com', port=443): Max retries exceeded
- Cause 1 (60%): DNS resolution failure. The Pi is connected to the router, but the router's DHCP didn't assign a valid DNS server. Fix: Hardcode
nameserver 1.1.1.1in/etc/resolv.conftemporarily to test. - Cause 2 (30%): The Wi-Fi associated, but the router blocked the Pi's MAC address or requires a captive portal login.
- Cause 3 (10%): SDIO bus dropout due to power ripple. The Wi-Fi chip temporarily vanished from the PCIe/SDIO bus. Check your power supply.
OSError: [Errno 101] Network is unreachable
- Cause 1 (80%): The
wlan0interface is down or lacks an IP address. Fix: Runnmcli device statusto see if wlan0 is 'connected' or 'disconnected'. - Cause 2 (20%): You are trying to route traffic out of
eth0but the Ethernet cable is unplugged, and the OS routing table prioritizes Ethernet over Wi-Fi.
Extending and Simplifying the Build
Depending on your project scope, you might need to scale this setup up or strip it down.
How to Simplify (The Ping-Monitor Route)
If you don't actually need environmental data and just want to use the Pi 3 as a network watchdog to monitor your home Wi-Fi's uptime, drop the BME280 entirely. Remove the smbus2 and bme280 imports. Replace the sensor read function with a simple subprocess.run(['ping', '-c', '4', '8.8.8.8']) call. Parse the standard output for packet loss percentages and push that to your dashboard. This reduces your hardware BOM to just the Pi, a case, and a power supply.
How to Extend (The MQTT Route)
HTTP POST requests are heavy and block the thread. For a production-grade IoT node, swap the requests library for paho-mqtt.
- Install the library:
pip3 install paho-mqtt. - Configure a persistent MQTT connection to a local Mosquitto broker or AWS IoT Core.
- Add a
client.publish('home/sensors/pi3', json.dumps(payload))call. - Implement MQTT Last Will and Testament (LWT) so your broker instantly knows when the Pi 3 loses Wi-Fi and drops offline.






