Simple, human Python API to control your device's wireless connectivity. Allows you to:
- Switch between client and hotspot modes
- Scan for networks in client mode
- Add and remove networks in the wpa_supplicant
- Connect to a certain or any network
- Add handlers to certain network-related events, like switching modes or a successful connection
The project was originally started as a part of ReachView, the software powering Emlid Reach receivers. However, it was written with any modern Linux distro in mind. As long as you comply with the dependencies listed below, it will work.
This package uses D-Bus to control systemd and wpa_supplicant. You need to have D-Bus itself and its python bindings in order to use this library. For example, on Ubuntu you need to install the following packages:
sudo apt install dbus libdbus-glib-1-dev libdbus-1-dev python-dbus
The D-Bus is used to control wpa_supplicant and hostapd systemd services. Stopping one of them and starting the other should be sufficient to actually turn on hotspot or get back to client mode on your system.
The project also relies on the following python packages:
The setup.py does not contain the python dependencies and you have to install them manually.
The wificontrol package has been tested and used with Python 2.7. Python 3.5 should also work with minor modifications, if any.
Practically everything wificontrol does, requires root access.
>>> import wificontrol
>>> wifi = wificontrol.WiFiControl()
>>> wifi.get_status()
('wpa_supplicant', {'IP address': '192.168.1.17', 'ssid': 'MYNETWORK', 'mac address': '9f:b6:86:0f:19:93'})
>>> wifi.start_host_mode()
True
>>> wifi.start_client_mode()
True
>>> wifi.scan()
>>> wifi.get_scan_results()
[{'security': 'WPA2-PSK', 'connected': False, 'ssid': 'reach:db:76'}, ...]
>>> wifi.add_network({'security': 'wpa2psk', 'ssid': 'reach:db:76', 'password': 'emlidreach', 'identity': ''})
>>> # the following method is non-blocking, but offers a callback option
...
>>> wifi.start_connecting({'ssid': 'reach:db:76'})
>>> wifi.get_status()
('wpa_supplicant', {'IP address': u'192.168.42.21', 'ssid': 'reach:db:76', 'mac address': u'90:b6:86:0f:19:93'})
All methods might raise the wificontrol.WiFiControlError
if something does not go according to plan.
If you don't have hostapd or wpa_supplicant package, WiFiControl will raise an OSError
exception.
All methods are blocking unless specified otherwise. Some, like scan()
, might take a while to complete.
WiFiControl()
constructor arguments:interface
: network interface name. Defaults towlan0
wpas_config
: path to wpa_supplicant.conf file. Defaults to:/etc/wpa_supplicant/wpa_supplicant.conf
p2p_config
: path to p2p_supplicant.conf file. Defaults to:/etc/wpa_supplicant/p2p_supplicant.conf
hostapd_config
: path to hostapd.conf file. Defaults to:/etc/hostapd/hostapd.conf
hostname_config
: path to hostname file. Defaults to:/etc/hostname
WiFiControl().turn_on_wifi()
- turn the wi-fi on usingrfkill
WiFiControl().turn_off_wifi()
- turn the wi-fi off usingrfkill
WiFiControl().is_wifi_on()
- return bool of whether the wi-fi is on
WiFiControl().start_host_mode()
- stop wpa_supplicant and start hostapdWiFiControl().start_client_mode()
- stop hostapd and start wpa_supplicant
WiFiControl().get_status()
- get wireless connection status. Returns(mode, network_info)
. Mode is on ofwpa_supplicant
orhostapd
.network_info
is a dict with fields'IP address', 'ssid', 'mac address'
WiFiControl().set_device_names(new_name)
- change hostname, p2p_name and Host AP SSID. Host AP SSID gets last 4 mac address digits appended in form ofreach:db:76
for uniquenessWiFiControl().get_device_name()
- returns device name stringWiFiControl().get_hostap_name()
- returns Host AP SSID name
WiFiControl().scan()
- scan for visible networks. Only works in client modeWiFiControl().get_scan_results()
- return a list of visible networks. Each network is represented with a dict with fields'security', 'ssid', 'mac address'
WiFiControl().get_added_networks()
- return a list of added networks. Each network is represented with a dict with fields'security', 'ssid', 'security'
WiFiControl().add_network({'security': security, 'ssid': ssid, 'password': psk, 'identity': identity})
- add a new network to the system and wpa_supplicant.conf. Security field is one of'open', 'wep', 'wpapsk', 'wpa2psk', 'wpaeap'
. Identity is only used for WPA2 Enterprise, but is always required to be in the dict.WiFiControl().remove_network({'ssid': ssid})
- remove network from the system and wpa_supplicant.confWiFiControl().start_connecting({'ssid': ssid}, callback=None, args=None, timeout=None)
- connect to one of the added networks. Add an optional callback function to execute after the connection process ended. The function's first argument will be a bool, representing connection success. Prototype looks like this:def foo(result, args):
WiFiControl().stop_connecting()
- stop the connection threadWiFiControl().disconnect()
- disconnect from the current network
Add handlers to wpa_supplicant and hostapd D-Bus events. Must be run in a separate process. D-Bus does not work with Python threads. Tools directory has a script and service files used to watch for network status on Reach.
import signal
from wificontrol import WiFiMonitor, WiFiControl
def main():
def handler(signum, frame):
wifi_monitor.shutdown()
def print_wifi_state():
print(WiFiControl().get_status())
wifi_monitor = WiFiMonitor()
wifi_monitor.register_callback(wifi_monitor.HOST_STATE, print_wifi_state)
wifi_monitor.register_callback(wifi_monitor.CLIENT_STATE, print_wifi_statete)
wifi_monitor.register_callback(wifi_monitor.OFF_STATE, print_wifi_statetate)
wifi_monitor.register_callback(wifi_monitor.SCAN_STATE, print_wifi_state)
wifi_monitor.register_callback(wifi_monitor.REVERT_EVENT, print_wifi_statetify)
wifi_monitor.register_callback(wifi_monitor.SUCCESS_EVENT, print_wifi_stateotify)
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
wifi_monitor.run()
if __name__ == '__main__':
main()
This package was written by Ivan Sapozhkov and Denis Chagin. It is used in Emlid's products, such as Reach and Reach RS.