python script for RaspberryPi to connect wifi automatically

Question:

I want to operate a WiFi dongle with RaspberryPi, (it’s like a CPU without built-in WiFi). I need to write a python script which automatically scan for WiFi networks and a connection need to be automatically established with known SSID and password.

This mean that I need to provide the password for the WiFi network from a file, and the
remaining thing is to do the scanning and connecting automatically.

I read a file from the Web which contains WiFi SSID name and password.

I need to write a script which scan and list current networds and match it to the SSID from the file and further to automatically create the connection to this known network.

RaspberryPi OS: Rasbian

Asked By: Vivekanand AIML

||

Answers:

wifi is a python library for scanning and connecting to wifi networks on linux. You can use it to scan and connect to wireless networks.

It doesn’t have any built-in support for connecting automatically to a network, but you could easily write a script to do that. Here’s an example of a basic idea for how to do this.

#!/usr/bin/python
from __future__ import print_function

from wifi import Cell, Scheme

# get all cells from the air
ssids = [cell.ssid for cell in Cell.all('wlan0')]

schemes = list(Scheme.all())

for scheme in schemes:
    ssid = scheme.options.get('wpa-ssid', scheme.options.get('wireless-essid'))
    if ssid in ssids:
        print('Connecting to %s' % ssid)
        scheme.activate()
        break

I just wrote it and it seems to work. Just so you know, I wrote the wifi library. If you want me to add this feature to that library, I could.

Answered By: rockymeza

This is a monkey patch of rockymeza’s answer above, so that the Scheme will use the /etc/wpa_supplicant/wpa_supplicant.conf file instead of the /etc/network/interfaces file. I couldn’t get his Scheme class to work on my pi3s as it seems like the Schemes just adds iface wlan0-SSIDname for each network to the /etc/network/interfaces file, and there is no mapping or anything to tell it that ifup wlan0-SSIDname is associated with ‘wlan0’.

import re
from wifi import Cell, Scheme
import wifi.subprocess_compat as subprocess
from wifi.utils import ensure_file_exists

class SchemeWPA(Scheme):

    interfaces = "/etc/wpa_supplicant/wpa_supplicant.conf"

    def __init__(self, interface, name, options=None):
        self.interface = interface
        self.name = name
        self.options = options or {} 

    def __str__(self):
        """
        Returns the representation of a scheme that you would need
        in the /etc/wpa_supplicant/wpa_supplicant.conf file.
        """

        options = ''.join("n    {k}="{v}"".format(k=k, v=v) for k, v in self.options.items())
        return "network={" + options + 'n}n'

    def __repr__(self):
            return 'Scheme(interface={interface!r}, name={name!r}, options={options!r}'.format(**vars(self))
    def save(self):
        """
        Writes the configuration to the :attr:`interfaces` file.
        """
        if not self.find(self.interface, self.name):
            with open(self.interfaces, 'a') as f:
                f.write('n')
                f.write(str(self))        

    @classmethod
    def all(cls):
        """
        Returns an generator of saved schemes.
        """
        ensure_file_exists(cls.interfaces)
        with open(cls.interfaces, 'r') as f:
            return extract_schemes(f.read(), scheme_class=cls) 
    def activate(self):
        """
        Connects to the network as configured in this scheme.
        """

        subprocess.check_output(['/sbin/ifdown', self.interface], stderr=subprocess.STDOUT)
        ifup_output = subprocess.check_output(['/sbin/ifup', self.interface] , stderr=subprocess.STDOUT)
        ifup_output = ifup_output.decode('utf-8')

        return self.parse_ifup_output(ifup_output)
    def delete(self):
        """
        Deletes the configuration from the /etc/wpa_supplicant/wpa_supplicant.conf file.
        """
        content = ''
        with open(self.interfaces, 'r') as f:
            lines=f.read().splitlines()
            while lines:
                line=lines.pop(0)

                if line.startswith('#') or not line:
                    content+=line+"n"
                    continue

                match = scheme_re.match(line)
                if match:
                    options = {}
                    ssid=None
                    content2=line+"n"
                    while lines and lines[0].startswith(' '):
                        line=lines.pop(0)
                        content2+=line+"n"
                        key, value = re.sub(r's{2,}', ' ', line.strip()).split('=', 1)
                        #remove any surrounding quotes on value
                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]
                        #store key, value
                        options[key] = value
                        #check for ssid (scheme name)
                        if key=="ssid":
                            ssid=value
                    #get closing brace        
                    line=lines.pop(0)
                    content2+=line+"n"

                    #exit if the ssid was not found so just add to content
                    if not ssid:
                        content+=content2
                        continue
                    #if this isn't the ssid then just add to content
                    if ssid!=self.name:
                        content+=content2

                else:
                    #no match so add content
                    content+=line+"n"
                    continue

        #Write the new content
        with open(self.interfaces, 'w') as f:
            f.write(content)    

scheme_re = re.compile(r'network={s?')


#override extract schemes
def extract_schemes(interfaces, scheme_class=SchemeWPA):
    lines = interfaces.splitlines()
    while lines:
        line = lines.pop(0)
        if line.startswith('#') or not line:
            continue

        match = scheme_re.match(line)
        if match:
            options = {}
            interface="wlan0"
            ssid=None

            while lines and lines[0].startswith(' '):
                key, value = re.sub(r's{2,}', ' ', lines.pop(0).strip()).split('=', 1)
                #remove any surrounding quotes on value
                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]
                #store key, value
                options[key] = value
                #check for ssid (scheme name)
                if key=="ssid":
                    ssid=value

            #exit if the ssid was not found
            if ssid is None:
                continue
            #create a new class with this info
            scheme = scheme_class(interface, ssid, options)

            yield scheme

To create the scheme, just do this:

scheme=SchemeWPA('wlan0',cell.ssid,{"ssid":cell.ssid,"psk":"yourpassword"})

Your /etc/network/interfaces file should look like this, or similar:

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual

allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

iface default inet dhcp

allow-hotplug wlan1
iface wlan1 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
Answered By: Captain Fantastic

Thank you all for your answers i made simple solution like below

def wifiscan():

   allSSID = Cell.all('wlan0')
   print allSSID # prints all available WIFI SSIDs
   myssid= 'Cell(ssid=vivekHome)' # vivekHome is my wifi name

   for i in range(len(allSSID )):
        if str(allSSID [i]) == myssid:
                a = i
                myssidA = allSSID [a]
                print b
                break
        else:
                print "getout"

   # Creating Scheme with my SSID.
   myssid= Scheme.for_cell('wlan0', 'home', myssidA, 'vivek1234') # vive1234 is the password to my wifi myssidA is the wifi name 

   print myssid
   myssid.save()
   myssid.activate()

wifiscan()   
Answered By: Vivekanand AIML

You can use the natively available network manager cli package (nmcli):

import subprocess

def what_wifi():
    process = subprocess.run(['nmcli', '-t', '-f', 'ACTIVE,SSID', 'dev', 'wifi'], stdout=subprocess.PIPE)
    if process.returncode == 0:
        return process.stdout.decode('utf-8').strip().split(':')[1]
    else:
        return ''

def is_connected_to(ssid: str):
    return what_wifi() == ssid

def scan_wifi():
    process = subprocess.run(['nmcli', '-t', '-f', 'SSID,SECURITY,SIGNAL', 'dev', 'wifi'], stdout=subprocess.PIPE)
    if process.returncode == 0:
        return process.stdout.decode('utf-8').strip().split('n')
    else:
        return []
        
def is_wifi_available(ssid: str):
    return ssid in [x.split(':')[0] for x in scan_wifi()]

def connect_to(ssid: str, password: str):
    if not is_wifi_available(ssid):
        return False
    subprocess.call(['nmcli', 'd', 'wifi', 'connect', ssid, 'password', password])
    return is_connected_to(ssid)

def connect_to_saved(ssid: str):
    if not is_wifi_available(ssid):
        return False
    subprocess.call(['nmcli', 'c', 'up', ssid])
    return is_connected_to(ssid)

Connect to a saved network:

connect_to_saved('my_wifi')

Otherwise, connect to a network with ssid and password:

connect_to('my_wifi', 'my_password')
Answered By: Anthony
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.