mirror of
https://github.com/markqvist/Sideband.git
synced 2025-08-03 12:06:07 -04:00
Included local plyer
This commit is contained in:
parent
25f0d52260
commit
f23855fb68
166 changed files with 15862 additions and 0 deletions
482
sbapp/plyer/platforms/linux/wifi.py
Normal file
482
sbapp/plyer/platforms/linux/wifi.py
Normal file
|
@ -0,0 +1,482 @@
|
|||
'''
|
||||
.. note::
|
||||
This facade depends on `nmcli` (Network Manager command line tool).
|
||||
It's found in most of the popular GNU/Linux distributions. Support for other
|
||||
backends is not provided yet.
|
||||
'''
|
||||
|
||||
from subprocess import Popen, PIPE, call
|
||||
from plyer.facades import Wifi
|
||||
from plyer.utils import whereis_exe, deprecated
|
||||
|
||||
try:
|
||||
import wifi
|
||||
except ModuleNotFoundError as err:
|
||||
raise ModuleNotFoundError(
|
||||
"python-wifi not installed. try:" +
|
||||
"`pip install --user wifi`.") from err
|
||||
|
||||
|
||||
class NMCLIWifi(Wifi):
|
||||
'''
|
||||
.. versionadded:: 1.4.0
|
||||
'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
.. versionadded:: 1.4.0
|
||||
'''
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.names = {}
|
||||
|
||||
@property
|
||||
def interfaces(self):
|
||||
'''
|
||||
Get all the available interfaces for WiFi.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self._is_enabled():
|
||||
self._enable()
|
||||
|
||||
# fetch the devices
|
||||
proc = Popen([
|
||||
'nmcli', '--terse',
|
||||
'--fields', 'DEVICE,TYPE',
|
||||
'device'
|
||||
], stdout=PIPE)
|
||||
lines = proc.communicate()[0].decode('utf-8').splitlines()
|
||||
|
||||
# filter devices by type
|
||||
interfaces = []
|
||||
for line in lines:
|
||||
# bad escape from nmcli's side :<
|
||||
line = line.replace('\\:', '$$')
|
||||
device, dtype = line.split(':')
|
||||
if dtype != 'wifi':
|
||||
continue
|
||||
interfaces.append(device.replace('$$', ':'))
|
||||
|
||||
# return wifi interfaces
|
||||
return interfaces
|
||||
|
||||
def _is_enabled(self):
|
||||
'''
|
||||
Return the status of WiFi device.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
output = Popen(
|
||||
["nmcli", "radio", "wifi"],
|
||||
stdout=PIPE
|
||||
).communicate()[0].decode('utf-8')
|
||||
|
||||
if output.split()[0] == 'enabled':
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_connected(self, interface=None):
|
||||
'''
|
||||
Return whether a specified interface is connected to a WiFi network.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self._is_enabled():
|
||||
self._enable()
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
# fetch all devices
|
||||
proc = Popen([
|
||||
'nmcli', '--terse',
|
||||
'--fields', 'DEVICE,TYPE,STATE',
|
||||
'device'
|
||||
], stdout=PIPE)
|
||||
lines = proc.communicate()[0].decode('utf-8').splitlines()
|
||||
|
||||
# filter by wifi type and interface
|
||||
connected = False
|
||||
for line in lines:
|
||||
line = line.replace('\\:', '$$')
|
||||
device, dtype, state = line.split(':')
|
||||
device = device.replace('$$', ':')
|
||||
if dtype != 'wifi':
|
||||
continue
|
||||
|
||||
if device != interface:
|
||||
continue
|
||||
|
||||
if state == 'connected':
|
||||
connected = True
|
||||
|
||||
return connected
|
||||
|
||||
def _start_scanning(self, interface=None):
|
||||
'''
|
||||
Start scanning for available Wi-Fi networks
|
||||
for the specified interface.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self._is_enabled():
|
||||
self._enable()
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
# force rescan for fresh data
|
||||
call(['nmcli', 'device', 'wifi', 'rescan', 'ifname', interface])
|
||||
|
||||
# get properties
|
||||
fields = [
|
||||
'SSID', 'BSSID', 'MODE', 'CHAN', 'FREQ',
|
||||
'BARS', 'RATE', 'SIGNAL', 'SECURITY'
|
||||
]
|
||||
|
||||
# fetch all networks for interface
|
||||
output = Popen([
|
||||
'nmcli', '--terse',
|
||||
'--fields', ','.join(fields),
|
||||
'device', 'wifi', 'list', 'ifname', interface
|
||||
], stdout=PIPE).communicate()[0].decode('utf-8')
|
||||
|
||||
# parse output
|
||||
for line in output.splitlines():
|
||||
line = line.replace('\\:', '$$')
|
||||
row = {
|
||||
field: value
|
||||
for field, value in zip(fields, line.split(':'))
|
||||
}
|
||||
|
||||
row['BSSID'] = row['BSSID'].replace('$$', ':')
|
||||
self.names[row['SSID']] = row
|
||||
|
||||
def _get_network_info(self, name):
|
||||
'''
|
||||
Get all the network information by network's name (SSID).
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self.names:
|
||||
self._start_scanning()
|
||||
|
||||
ret_list = {}
|
||||
ret_list['ssid'] = self.names[name]['SSID']
|
||||
ret_list['signal'] = self.names[name]['SIGNAL']
|
||||
|
||||
bars = len(self.names[name]['BARS'])
|
||||
ret_list['quality'] = '{}/100'.format(bars / 5.0 * 100)
|
||||
ret_list['frequency'] = self.names[name]['FREQ']
|
||||
ret_list['bitrates'] = self.names[name]['RATE']
|
||||
|
||||
# wpa1, wpa2, wpa1 wpa2, wep, (none), perhaps something else
|
||||
security = self.names[name]['SECURITY'].lower()
|
||||
ret_list['encrypted'] = True
|
||||
if 'wpa2' in security:
|
||||
# wpa2, wpa2+wpa1
|
||||
ret_list['encryption_type'] = 'wpa2'
|
||||
elif 'wpa' in security:
|
||||
ret_list['encryption_type'] = 'wpa'
|
||||
elif 'wep' in security:
|
||||
ret_list['encryption_type'] = 'wep'
|
||||
elif 'none' in security:
|
||||
ret_list['encrypted'] = False
|
||||
ret_list['encryption_type'] = 'none'
|
||||
else:
|
||||
ret_list['encryption_type'] = security
|
||||
|
||||
ret_list['channel'] = int(self.names[name]['CHAN'])
|
||||
ret_list['address'] = self.names[name]['BSSID']
|
||||
ret_list['mode'] = self.names[name]['MODE']
|
||||
return ret_list
|
||||
|
||||
def _get_available_wifi(self):
|
||||
'''
|
||||
Return the names of all found networks.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self.names:
|
||||
self._start_scanning()
|
||||
return list(self.names.keys())
|
||||
|
||||
def _connect(self, network, parameters, interface=None):
|
||||
'''
|
||||
Connect a specific interface to a WiFi network.
|
||||
|
||||
Expects 2 parameters:
|
||||
- SSID of the network
|
||||
- parameters: dict
|
||||
- password: string or None
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
self._enable()
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
password = parameters.get('password')
|
||||
command = [
|
||||
'nmcli', 'device', 'wifi', 'connect', network,
|
||||
'ifname', interface
|
||||
]
|
||||
if password:
|
||||
command += ['password', password]
|
||||
call(command)
|
||||
|
||||
def _disconnect(self, interface=None):
|
||||
'''
|
||||
Disconnect a specific interface from a WiFi network.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
if not self._is_enabled():
|
||||
return
|
||||
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
if self._nmcli_version() >= (1, 2, 6):
|
||||
call(['nmcli', 'device', 'disconnect', interface])
|
||||
else:
|
||||
call(['nmcli', 'nm', 'enable', 'false'])
|
||||
|
||||
def _enable(self):
|
||||
'''
|
||||
Turn WiFi device on.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
call(['nmcli', 'radio', 'wifi', 'on'])
|
||||
|
||||
def _disable(self):
|
||||
'''
|
||||
Turn WiFi device off.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
call(['nmcli', 'radio', 'wifi', 'off'])
|
||||
|
||||
def _nmcli_version(self):
|
||||
'''
|
||||
Get nmcli version to prevent executing deprecated commands.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
Tested with nmcli 1.2.6.
|
||||
'''
|
||||
version = Popen(['nmcli', '-v'], stdout=PIPE)
|
||||
version = version.communicate()[0].decode('utf-8')
|
||||
while version and not version[0].isdigit():
|
||||
version = version[1:]
|
||||
return tuple(map(int, (version.split('.'))))
|
||||
|
||||
|
||||
@deprecated
|
||||
class LinuxWifi(Wifi):
|
||||
'''
|
||||
.. versionadded:: 1.2.5
|
||||
'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
.. versionadded:: 1.4.0
|
||||
'''
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.names = {}
|
||||
|
||||
@property
|
||||
def interfaces(self):
|
||||
'''
|
||||
.. versionadded:: 1.4.0
|
||||
'''
|
||||
|
||||
proc = Popen([
|
||||
'nmcli', '--terse',
|
||||
'--fields', 'DEVICE,TYPE',
|
||||
'device'
|
||||
], stdout=PIPE)
|
||||
lines = proc.communicate()[0].decode('utf-8').splitlines()
|
||||
|
||||
interfaces = []
|
||||
for line in lines:
|
||||
device, dtype = line.split(':')
|
||||
if dtype != 'wifi':
|
||||
continue
|
||||
interfaces.append(device)
|
||||
|
||||
return interfaces
|
||||
|
||||
def _is_enabled(self):
|
||||
'''
|
||||
Returns `True` if wifi is enabled else `False`.
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
.. versionchanged:: 1.3.2
|
||||
nmcli output is properly decoded to unicode
|
||||
'''
|
||||
enbl = Popen(["nmcli", "radio", "wifi"], stdout=PIPE, stderr=PIPE)
|
||||
if enbl.communicate()[0].split()[0].decode('utf-8') == "enabled":
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_connected(self, interface=None):
|
||||
'''
|
||||
.. versionadded:: 1.4.0
|
||||
'''
|
||||
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
proc = Popen([
|
||||
'nmcli', '--terse',
|
||||
'--fields', 'DEVICE,TYPE,STATE',
|
||||
'device'
|
||||
], stdout=PIPE)
|
||||
lines = proc.communicate()[0].decode('utf-8').splitlines()
|
||||
|
||||
connected = False
|
||||
for line in lines:
|
||||
device, dtype, state = line.split(':')
|
||||
if dtype != 'wifi':
|
||||
continue
|
||||
|
||||
if device != interface:
|
||||
continue
|
||||
|
||||
if state == 'connected':
|
||||
connected = True
|
||||
|
||||
return connected
|
||||
|
||||
def _start_scanning(self, interface=None):
|
||||
'''
|
||||
Returns all the network information.
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
.. versionchanged:: 1.3.0
|
||||
scan only if wifi is enabled
|
||||
'''
|
||||
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
if self._is_enabled():
|
||||
list_ = list(wifi.Cell.all(interface))
|
||||
for i in range(len(list_)):
|
||||
self.names[list_[i].ssid] = list_[i]
|
||||
else:
|
||||
raise Exception('Wifi not enabled.')
|
||||
|
||||
def _get_network_info(self, name):
|
||||
'''
|
||||
Starts scanning for available Wi-Fi networks and returns the available,
|
||||
devices.
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
'''
|
||||
ret_list = {}
|
||||
ret_list['ssid'] = self.names[name].ssid
|
||||
ret_list['signal'] = self.names[name].signal
|
||||
ret_list['quality'] = self.names[name].quality
|
||||
ret_list['frequency'] = self.names[name].frequency
|
||||
ret_list['bitrates'] = self.names[name].bitrates
|
||||
ret_list['encrypted'] = self.names[name].encrypted
|
||||
ret_list['channel'] = self.names[name].channel
|
||||
ret_list['address'] = self.names[name].address
|
||||
ret_list['mode'] = self.names[name].mode
|
||||
if not ret_list['encrypted']:
|
||||
return ret_list
|
||||
else:
|
||||
ret_list['encryption_type'] = self.names[name].encryption_type
|
||||
return ret_list
|
||||
|
||||
def _get_available_wifi(self):
|
||||
'''
|
||||
Returns the name of available networks.
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
.. versionchanged:: 1.4.0
|
||||
return a proper list of elements instead of dict_keys
|
||||
'''
|
||||
return list(self.names.keys())
|
||||
|
||||
def _connect(self, network, parameters, interface=None):
|
||||
'''
|
||||
Expects 2 parameters:
|
||||
- name/ssid of the network.
|
||||
- parameters: dict type
|
||||
- password: string or None
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
'''
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
result = None
|
||||
try:
|
||||
self._enable()
|
||||
finally:
|
||||
password = parameters['password']
|
||||
cell = self.names[network]
|
||||
result = wifi.Scheme.for_cell(
|
||||
interface, network, cell, password
|
||||
)
|
||||
return result
|
||||
|
||||
def _disconnect(self, interface=None):
|
||||
'''
|
||||
Disconnect all the networks managed by Network manager.
|
||||
|
||||
.. versionadded:: 1.2.5
|
||||
'''
|
||||
if not interface:
|
||||
interface = self.interfaces[0]
|
||||
|
||||
if self._nmcli_version() >= (1, 2, 6):
|
||||
call(['nmcli', 'dev', 'disconnect', interface])
|
||||
else:
|
||||
call(['nmcli', 'nm', 'enable', 'false'])
|
||||
|
||||
def _enable(self):
|
||||
'''
|
||||
Wifi interface power state is set to "ON".
|
||||
|
||||
.. versionadded:: 1.3.2
|
||||
'''
|
||||
return call(['nmcli', 'radio', 'wifi', 'on'])
|
||||
|
||||
def _disable(self):
|
||||
'''
|
||||
Wifi interface power state is set to "OFF".
|
||||
|
||||
.. versionadded:: 1.3.2
|
||||
'''
|
||||
return call(['nmcli', 'radio', 'wifi', 'off'])
|
||||
|
||||
def _nmcli_version(self):
|
||||
'''
|
||||
.. versionadded:: 1.3.2
|
||||
'''
|
||||
version = Popen(['nmcli', '-v'], stdout=PIPE)
|
||||
version = version.communicate()[0].decode('utf-8')
|
||||
while version and not version[0].isdigit():
|
||||
version = version[1:]
|
||||
return tuple(map(int, (version.split('.'))))
|
||||
|
||||
|
||||
def instance():
|
||||
if whereis_exe('nmcli'):
|
||||
return NMCLIWifi()
|
||||
|
||||
return LinuxWifi()
|
Loading…
Add table
Add a link
Reference in a new issue