awkman / pywifi

A cross-platform module for manipulating WiFi devices.
MIT License
447 stars 154 forks source link

How can I find out when Wi-Fi scan is complete? #54

Open 1oh1 opened 4 years ago

1oh1 commented 4 years ago

This code doesn't work without a timeout between the scan and the scan_results method on Windows:

import pywifi, logging
wifi = pywifi.PyWiFi()
wifi._logger.setLevel(logging.DEBUG)
interfaces = wifi.interfaces()

for interface in interfaces:
    interface.scan()
    print (interface.scan_results())

Result:

>>> import pywifi, logging
>>> wifi = pywifi.PyWiFi()
>>> wifi._logger.setLevel(logging.DEBUG)
>>> interfaces = wifi.interfaces()
pywifi 2019-11-06 02:24:36,376 INFO Get interface: Qualcomm Atheros QCA9377 Wireless Network Adapter
>>>
>>> for interface in interfaces:
...     interface.scan()
...     print (interface.scan_results())
...
pywifi 2019-11-06 02:24:36,569 INFO iface 'Qualcomm Atheros QCA9377 Wireless Network Adapter' scans
pywifi 2019-11-06 02:24:36,571 DEBUG Scan found 15 networks.
[]
>>> # after a second
...
>>> interfaces[0].scan_results()
pywifi 2019-11-06 02:25:02,709 DEBUG Scan found 13 networks.
pywifi 2019-11-06 02:25:02,712 INFO Find bss:
...TRUNCATED...
pywifi 2019-11-06 02:25:02,752 INFO Find bss:
pywifi 2019-11-06 02:25:02,753 INFO     bssid: bc:34:00:11:7d:42:
pywifi 2019-11-06 02:25:02,753 INFO     ssid: APW40-01
pywifi 2019-11-06 02:25:02,753 INFO     freq: 2462000
pywifi 2019-11-06 02:25:02,754 INFO     auth: [0]
pywifi 2019-11-06 02:25:02,754 INFO     akm: [4]
pywifi 2019-11-06 02:25:02,755 INFO     signal: -83
[<pywifi.profile.Profile object at 0x0338A058>, <pywifi.profile.Profile object at 0x0336B940>, <pywifi.profile.Profile object at 0x0336BCE8>, <pywifi.profile.Profile object at 0x0336BEE0>, <pywifi.profile.Profile object at 0x0336BCA0>, <pywifi.profile.Profile object at 0x0336BB80>, <pywifi.profile.Profile object at 0x033BBD60>, <pywifi.profile.Profile object at 0x033BBD78>, <pywifi.profile.Profile object at 0x033BBF40>, <pywifi.profile.Profile object at 0x033BBF88>, <pywifi.profile.Profile object at 0x033BBB98>, <pywifi.profile.Profile object at 0x033BBD18>, <pywifi.profile.Profile object at 0x03562328>]

Would it be possible for scan to not finish before scan_results has the data available?

Another issue I noticed was that if I simply loop until scan_results doesn't return an empty list, the output I get is a list of just one or a subset of the Wi-Fi networks from the scan. If I call scan_results a second later (without calling scan again) it'll have the complete list of networks:

Code:

import pywifi, itertools, sys, time
from datetime import datetime

wifi = pywifi.PyWiFi()
interfaces = wifi.interfaces()
networks = []
timeout = 5
start_time = time.time()

for interface in interfaces:
    interface.scan()

while time.time() < start_time + timeout and networks == []:
    for interface in interfaces:
        if interface.scan_results() == []:
            print ("{}: nothing yet".format(datetime.now().isoformat(sep=' ', timespec='milliseconds')))
            continue
        else:
            print ([x.ssid for x in interface.scan_results()])
            for network in interface.scan_results():
                networks += [(network.bssid, network.signal, network.ssid, network.key, network.id, network.cipher, network.freq, network.auth, network.akm)]
            print ("Waiting half a second")
            time.sleep(0.5)
            print ([x.ssid for x in interface.scan_results()])
            print ("Waiting 1 second")
            time.sleep(1)
            print ([x.ssid for x in interface.scan_results()])
            break

Result:

C:\Users\1oh1\Desktop>python3 scan-wifi.py
2019-11-06 03:07:22.903: nothing yet
2019-11-06 03:07:22.904: nothing yet
2019-11-06 03:07:22.904: nothing yet
2019-11-06 03:07:22.905: nothing yet
2019-11-06 03:07:22.905: nothing yet
2019-11-06 03:07:22.906: nothing yet
2019-11-06 03:07:22.906: nothing yet
2019-11-06 03:07:22.906: nothing yet
2019-11-06 03:07:22.907: nothing yet
2019-11-06 03:07:22.907: nothing yet
2019-11-06 03:07:22.908: nothing yet
2019-11-06 03:07:22.908: nothing yet
2019-11-06 03:07:22.908: nothing yet
2019-11-06 03:07:22.909: nothing yet
2019-11-06 03:07:22.909: nothing yet
2019-11-06 03:07:22.910: nothing yet
2019-11-06 03:07:22.910: nothing yet
2019-11-06 03:07:22.910: nothing yet
2019-11-06 03:07:22.911: nothing yet
['Tails_5G', 'Tails_5G']
Waiting half a second
['Tails_5G', 'D-Link_DIR-615', 'Subhashchandra', 'Subhashchandra', 'APW40-01', 'Xiaomi_779F', 'Ridhi', 'D-Link_DIR-615', 'Tails_5G']
Waiting 1 second
['Tails_5G', 'Tails', 'D-Link_DIR-615', 'Tails_5G', 'Xiaomi_779F', 'Chitra N', 'Tails', 'Falcons Indane', 'Subhashchandra', 'Subhashchandra', 'APW40-01', 'Ridhi', 'D-Link_DIR-615']

It'd be nice if scan_results either returned an empty list or the complete list of networks instead of returning whatever it has at that point of time.