Cross-platform Wi-Fi controller with pluggable providers for macOS, Linux, and Windows.
Project description
wifi-controller
A cross-platform Wi-Fi controller for Python with pluggable provider architecture. Supports macOS and Linux out of the box, with an optional Swift-based scanner for macOS 15+ where Apple redacts SSIDs without Location Services authorization.
Features
- Cross-platform -- built-in providers for macOS (
networksetup,ipconfig,system_profiler) and Linux (nmcli,iwgetid) - Pluggable providers -- register your own scan/connect/disconnect implementations with priority-based resolution
- macOS SSID redaction workaround -- optional Swift scanner (
extras/ssid_scanner/) uses CoreWLAN + CoreLocation to return real SSIDs on macOS 15+ - Zero dependencies -- pure Python, stdlib only
Installation
pip install wifi-controller
Or with Poetry:
poetry add wifi-controller
Quick Start
from wifi_controller import WiFiController
wifi = WiFiController()
# Get current network
ssid = wifi.get_current_ssid()
print(f"Connected to: {ssid}")
# Scan nearby networks
networks = wifi.scan()
for net in networks:
print(f" {net.ssid} (RSSI={net.rssi}, CH={net.channel})")
# Connect to a network
wifi.connect("MyNetwork", "hunter2")
# Poll for a specific SSID
found = wifi.scan_for_ssid("MyNetwork", timeout_sec=30)
# Disconnect
wifi.disconnect()
macOS 15+ SSID Redaction
Starting with macOS 15 (Sequoia), Apple redacts SSID information from
system_profiler, CoreWLAN, and other system APIs unless the calling process
has Location Services authorization via a signed app bundle.
The built-in Python providers cannot work around this limitation. To get
real SSIDs on macOS 15+, build the Swift scanner from extras/ssid_scanner/:
# Prerequisites: Xcode Command Line Tools + Apple Development certificate
make -C extras/ssid_scanner check # verify prerequisites
make -C extras/ssid_scanner all # build and sign
Then register the Swift providers:
from wifi_controller import WiFiController
from wifi_controller._swift import (
SwiftSsidScannerCurrentSSID,
SwiftSsidScannerScan,
SwiftSsidScannerConnect,
SwiftSsidScannerDisconnect,
)
wifi = WiFiController()
binary = "extras/ssid_scanner/ssid_scanner" # path to built binary
wifi.register_scan_provider(SwiftSsidScannerScan(binary), priority=10)
wifi.register_current_ssid_provider(SwiftSsidScannerCurrentSSID(binary), priority=10)
wifi.register_connect_provider(SwiftSsidScannerConnect(binary), priority=10)
wifi.register_disconnect_provider(SwiftSsidScannerDisconnect(binary), priority=10)
# Now scan() returns real SSIDs on macOS 15+
networks = wifi.scan()
Custom Providers
Implement any of the four provider ABCs to add support for additional tools:
from wifi_controller import WiFiController, SSIDScanProvider, SSIDInfo
class MyCustomScanner(SSIDScanProvider):
@property
def name(self) -> str:
return "my_scanner"
def is_available(self) -> bool:
return True # check if your tool is installed
def scan_ssids(self, interface: str, timeout: int = 15) -> list[SSIDInfo]:
# ... your implementation ...
return [SSIDInfo(ssid="Example", bssid="00:11:22:33:44:55", rssi=-42, channel=6)]
wifi = WiFiController()
wifi.register_scan_provider(MyCustomScanner(), priority=20)
Provider ABCs:
| ABC | Operation |
|---|---|
CurrentSSIDProvider |
Get the currently-connected SSID |
SSIDScanProvider |
Scan for nearby networks |
SSIDConnectProvider |
Connect to a network (SSID + password) |
SSIDDisconnectProvider |
Disconnect from the current network |
Higher priority providers are tried first. The first provider whose
is_available() returns True is used and cached for subsequent calls.
Project Layout
wifi_controller/
├── src/wifi_controller/ # Python package (ships on PyPI)
│ ├── __init__.py # WiFiController orchestrator
│ ├── _types.py # SSIDInfo, WiFiConnectionError
│ ├── _abc.py # Four provider ABCs
│ ├── _macos.py # Built-in macOS providers
│ ├── _linux.py # Built-in Linux providers
│ └── _swift.py # Python wrappers for Swift binary
├── extras/ssid_scanner/ # Swift source (not on PyPI, clone to use)
│ ├── scan.swift # CoreWLAN + CoreLocation scanner
│ ├── Makefile # Build, sign, test
│ └── *.plist # App bundle configuration
├── docs/ # Architecture diagrams (PlantUML)
└── tests/ # Unit tests
Architecture
See docs/ for PlantUML diagrams covering:
- Class diagram -- provider ABCs, WiFiController, built-in implementations
- Sequence diagram -- provider resolution and operation flow
- Component diagram -- package structure and platform boundaries
Development
# Install dev dependencies
poetry install
# Run tests
poetry run pytest
# Lint
poetry run ruff check src/ tests/
# Format
poetry run ruff format src/ tests/
License
MIT -- see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wifi_controller-0.1.0.tar.gz.
File metadata
- Download URL: wifi_controller-0.1.0.tar.gz
- Upload date:
- Size: 12.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.10.14 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20eec083030f47281be12b69aac11068254c5baed11d801999cd8b1054ecaafa
|
|
| MD5 |
b10cdfec01a60048078c75e9066c1d27
|
|
| BLAKE2b-256 |
1d6ac3163111322ffe4fd1feb24659e220451226bccbb45a24791dd4be4a9609
|
File details
Details for the file wifi_controller-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wifi_controller-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.10.14 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e1838f47b6b029e3d71f07d1a5c310b2f1b22f4bdbcb2a95aba0d941fed1991
|
|
| MD5 |
ae3c025c813134e8d58aaefa815e458a
|
|
| BLAKE2b-256 |
e6be474a3cad541dbcb4c4994153a5a59d831c481ad549e4b1af9eb781256acb
|