GithubHelp home page GithubHelp logo

emlid / pywificontrol Goto Github PK

View Code? Open in Web Editor NEW
115.0 28.0 49.0 252 KB

Python API to control Wi-Fi connectivity

Home Page: https://emlid.com

License: BSD 3-Clause "New" or "Revised" License

Python 99.81% Makefile 0.19%

pywificontrol's Introduction

Python API to control Wi-Fi connectivity

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.

Prerequisites

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.

WiFiControl Examples
Checking connection status
>>> 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'})
Switching modes
>>> wifi.start_host_mode()
True
>>> wifi.start_client_mode()
True
Scanning and connecting
>>> 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'})
WiFiControl API

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 to wlan0
    • 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
Hardware control
  • WiFiControl().turn_on_wifi() - turn the wi-fi on using rfkill
  • WiFiControl().turn_off_wifi() - turn the wi-fi off using rfkill
  • WiFiControl().is_wifi_on() - return bool of whether the wi-fi is on
Mode switching
  • WiFiControl().start_host_mode() - stop wpa_supplicant and start hostapd
  • WiFiControl().start_client_mode() - stop hostapd and start wpa_supplicant
Status and naming
  • WiFiControl().get_status() - get wireless connection status. Returns (mode, network_info). Mode is on of wpa_supplicant or hostapd. 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 of reach:db:76 for uniqueness
  • WiFiControl().get_device_name() - returns device name string
  • WiFiControl().get_hostap_name() - returns Host AP SSID name
Scanning and working with networks
  • WiFiControl().scan() - scan for visible networks. Only works in client mode
  • WiFiControl().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.conf
  • WiFiControl().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 thread
  • WiFiControl().disconnect() - disconnect from the current network
WiFiMonitor daemon

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.

Usage Example

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()

Credits

This package was written by Ivan Sapozhkov and Denis Chagin. It is used in Emlid's products, such as Reach and Reach RS.

pywificontrol's People

Contributors

dskorykh avatar egorf avatar isapozhkov avatar merindorium avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pywificontrol's Issues

wificontrol.wificommon.WiFiControlError: WiFiControl: subprocess call error Return code: 1

Hey, I'm just trying to start on my raspberry pi an access point.
So I write this code:

import wificontrol

wifi = wificontrol.WiFiControl()
wifi.start_host_mode()

But when I run this code, its returns an exception:

Traceback (most recent call last):
  File "raspAP.py", line 4, in <module>
    wifi.start_host_mode()
  File "build/bdist.linux-armv7l/egg/wificontrol/wificontrol.py", line 60, in start_host_mode
  File "build/bdist.linux-armv7l/egg/wificontrol/hostapd.py", line 57, in start
  File "build/bdist.linux-armv7l/egg/wificontrol/wificommon.py", line 98, in execute_command
wificontrol.wificommon.WiFiControlError: WiFiControl: subprocess call error
Return code: 1
Command: systemctl start hostapd.service && sleep 2

So what this exception even mean ?

WiFiControl().start_connecting() not working. The thread just executes.

Hello, I am trying to use this API to connect to a network. As of docs, i could use start_connecting() method to connect to the required wireless network. But control is just getting in and out. Here's what i am trying to do:

>>> cont = wificontrol.WiFiControl(interface="wlan1")
>>> cont.scan()
>>> cont.get_scan_results()
       [{'security': 'wpapsk', 'ssid': 'unknown', 'mac address': '34:bf:90:4a:bb:57'}]
>>> cont.add_network({'security': 'wpapsk', 'ssid': 'unknown', 'password': '786 5555', 'identity':''})
>>> cont.start_connecting({'ssid':'unknown'}, callback=callBack)

After the last statement, nothing happens. The first argument from callBack gives False as well as the interface doesn't get connected to the network. However, the configuration seems all right.

Currently, i am stuck at this place. Hope you got it.

No module named 'reachstatus' and No module named 'hostapd'

Using latest Raspbian Stretch on a Pi Zero, after installing dependencies netifaces and systemd-manage and try to run usage example:

root@raspberrypi:/opt/pywificontrol/tools # ./wifimonitor
Traceback (most recent call last):
File "wifimonitor", line 40, in
from reachstatus import StateClient
ImportError: No module named 'reachstatus'

and
Traceback (most recent call last):
File "bla.py", line 1, in
import wificontrol
File "/opt/pywificontrol/wificontrol/init.py", line 1, in
from wificontrol import wificontrol
File "/opt/pywificontrol/wificontrol/wificontrol.py", line 36, in
from hostapd import HostAP
ImportError: No module named 'hostapd'

What else is needed?

Best regards,
Vuko

Remove the need for systemd

Please make the need for systemd optional so that it can work on non-systemd systems as well. Use case: Run this on FreeBSD.

Missing a config file for wpa_supplicant?

Hi thank you very much for open sourcing this. I have been trying to get this going on an Edison, but I keep getting an error:

File "build/bdist.linux-i686/egg/wificontrol/utils/dbuswpasupplicant.py", line 94, in get_interface
wificontrol.utils.dbuswpasupplicant.InterfaceError: fi.w1.wpa_supplicant1.InterfaceUnknown: wpa_supplicant knows nothing about this interface.

is there something I am missing regarding configuration of wpa_supplicant?

ImportError: No module named daemon_tree

Using latest Raspbian Stretch on a Pi Zero, after installing dependencies netifaces and systemd-manage and try to run usage example:

Traceback (most recent call last):
  File "wifi.py", line 2, in <module>
    from wificontrol import WiFiMonitor, WiFiControl
  File "build/bdist.linux-armv6l/egg/wificontrol/__init__.py", line 3, in <module>
  File "build/bdist.linux-armv6l/egg/wificontrol/wifimonitor.py", line 42, in <module>
ImportError: No module named daemon_tree

I cannot found any similar named package daemon_tree.
What else is needed?

Best regards,
Nic

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.