Skip to content

File WiFiMulti.cpp

File List > arduino > libraries > ext > WiFiMulti > WiFiMulti.cpp

Go to the documentation of this file.

#if LT_ARD_HAS_WIFI

#include "WiFiMulti.h"
#include <Arduino.h>
#include <limits.h>
#include <string.h>

WiFiMulti::WiFiMulti() {}

WiFiMulti::~WiFiMulti() {
    for (uint32_t i = 0; i < APlist.size(); i++) {
        WifiAPlist_t entry = APlist[i];
        if (entry.ssid) {
            free(entry.ssid);
        }
        if (entry.passphrase) {
            free(entry.passphrase);
        }
    }
    APlist.clear();
}

bool WiFiMulti::addAP(const char *ssid, const char *passphrase) {
    WifiAPlist_t newAP;

    if (!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
        // fail SSID too long or missing!
        LT_EM(WIFI, "SSID missing or too long");
        return false;
    }

    if (passphrase && strlen(passphrase) > 64) {
        // fail passphrase too long!
        LT_EM(WIFI, "Passphrase too long");
        return false;
    }

    newAP.ssid = strdup(ssid);

    if (!newAP.ssid) {
        LT_EM(WIFI, "Fail newAP.ssid == 0");
        return false;
    }

    if (passphrase && *passphrase != 0x00) {
        newAP.passphrase = strdup(passphrase);
        if (!newAP.passphrase) {
            LT_EM(WIFI, "Fail newAP.passphrase == 0");
            free(newAP.ssid);
            return false;
        }
    } else {
        newAP.passphrase = NULL;
    }

    APlist.push_back(newAP);
    LT_VM(WIFI, "Add SSID: %s", newAP.ssid);
    return true;
}

uint8_t WiFiMulti::run(uint32_t connectTimeout) {
    int8_t scanResult;
    uint8_t status = WiFi.status();
    if (status == WL_CONNECTED) {
        for (uint32_t x = 0; x < APlist.size(); x++) {
            if (WiFi.SSID() == APlist[x].ssid) {
                return status;
            }
        }
        WiFi.disconnect(false);
        delay(10);
        status = WiFi.status();
    }

    scanResult = WiFi.scanNetworks();
    if (scanResult == WIFI_SCAN_RUNNING) {
        // scan is running
        return WL_NO_SSID_AVAIL;
    } else if (scanResult >= 0) {
        // scan done analyze
        WifiAPlist_t bestNetwork{NULL, NULL};
        int bestNetworkDb = INT_MIN;
        uint8_t bestBSSID[6];
        int32_t bestChannel = 0;

        LT_IM(WIFI, "Scan finished");

        if (scanResult == 0) {
            LT_IM(WIFI, "No networks found");
        } else {
            LT_IM(WIFI, "%d networks found", scanResult);
            for (int8_t i = 0; i < scanResult; ++i) {

                String ssid_scan;
                int32_t rssi_scan;
                WiFiAuthMode sec_scan;
                uint8_t *BSSID_scan;
                int32_t chan_scan;

                WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan);

                bool known = false;
                for (uint32_t x = APlist.size(); x > 0; x--) {
                    WifiAPlist_t entry = APlist[x - 1];

                    if (ssid_scan == entry.ssid) { // SSID match
                        known = true;
                        if (rssi_scan > bestNetworkDb) { // best network
                            if (sec_scan == WIFI_AUTH_OPEN ||
                                entry.passphrase) { // check for passphrase if not open wlan
                                bestNetworkDb = rssi_scan;
                                bestChannel   = chan_scan;
                                memcpy((void *)&bestNetwork, (void *)&entry, sizeof(bestNetwork));
                                memcpy((void *)&bestBSSID, (void *)BSSID_scan, sizeof(bestBSSID));
                            }
                        }
                        break;
                    }
                }

                if (known) {
                    LT_DM(
                        WIFI,
                        " --->   %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c",
                        i,
                        chan_scan,
                        BSSID_scan[0],
                        BSSID_scan[1],
                        BSSID_scan[2],
                        BSSID_scan[3],
                        BSSID_scan[4],
                        BSSID_scan[5],
                        ssid_scan.c_str(),
                        rssi_scan,
                        (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*'
                    );
                } else {
                    LT_DM(
                        WIFI,
                        "       %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c",
                        i,
                        chan_scan,
                        BSSID_scan[0],
                        BSSID_scan[1],
                        BSSID_scan[2],
                        BSSID_scan[3],
                        BSSID_scan[4],
                        BSSID_scan[5],
                        ssid_scan.c_str(),
                        rssi_scan,
                        (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*'
                    );
                }
            }
        }

        // clean up ram
        WiFi.scanDelete();

        if (bestNetwork.ssid) {
            LT_IM(
                WIFI,
                "Connecting to BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)",
                bestBSSID[0],
                bestBSSID[1],
                bestBSSID[2],
                bestBSSID[3],
                bestBSSID[4],
                bestBSSID[5],
                bestNetwork.ssid,
                bestChannel,
                bestNetworkDb
            );

            WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
            status = WiFi.status();

            auto startTime = millis();
            // wait for connection, fail, or timeout
            while (status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED &&
                   (millis() - startTime) <= connectTimeout) {
                delay(10);
                status = WiFi.status();
            }

            IPAddress ip;
            switch (status) {
                case WL_CONNECTED:
                    LT_IM(WIFI, "Connecting done");
                    LT_DM(WIFI, "SSID: %s", WiFi.SSID().c_str());
                    // TODO fix this after implementing IP format for printf()
                    ip = WiFi.localIP();
                    LT_DM(WIFI, "IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
                    LT_DM(WIFI, "MAC: %s", WiFi.BSSIDstr().c_str());
                    LT_DM(WIFI, "Channel: %d", WiFi.channel());
                    break;
                case WL_NO_SSID_AVAIL:
                    LT_EM(WIFI, "Connecting failed; AP not found");
                    break;
                case WL_CONNECT_FAILED:
                    LT_EM(WIFI, "Connecting failed");
                    break;
                default:
                    LT_EM(WIFI, "Connecting failed (%d)", status);
                    break;
            }
        } else {
            LT_EM(WIFI, "No matching network found!");
        }
    } else {
        // start scan
        LT_VM(WIFI, "Delete old wifi config...");
        WiFi.disconnect();

        LT_DM(WIFI, "Start scan");
        // scan wifi async mode
        WiFi.scanNetworks(true);
    }

    return status;
}

#endif // LT_ARD_HAS_WIFI