Scanning for best ssid before connecting to IO

Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Locked
User avatar
JackTheSE
 
Posts: 54
Joined: Wed Jan 02, 2019 8:34 pm

Scanning for best ssid before connecting to IO

Post by JackTheSE »

Every example program for the AdafruitIO library presumes you know the target WiFi SSID before any code executes. But I would like to first scan for the access point with the strongest WiFi signal, and then connect to that one. I have a router and multiple WiFi extension access points in my house, each with a unique ssid, but with the same WiFi password. For many reasons, that circumstance cannot change.
The call to AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS) occurs before any code executes, and the WIFI_SSID argument is always set by a #define statement in the examples. I have also used const* char and cons char* variables successfully. I'm not enough of a C++ guru to know if there is any way to change the value of those arguments, before calling io.connect.
I have looked, but I don't see any function call in the AIO library that would allow me to reset the ssid after code execution starts, but before io.connect is called.
I have tried connecting to that best WiFi signal ssid, and then calling io.connect, but it immediately disconnects me and starts over with the preset ssid.
Any help on this would be greatly appreciated...

User avatar
mikeysklar
 
Posts: 14165
Joined: Mon Aug 01, 2016 8:10 pm

Re: Scanning for best ssid before connecting to IO

Post by mikeysklar »

Jack,

Would you like to post small example piece of code you are running (no passwords)?

I think you might be able to replace the #defines with arrays as is used in some of the other WiFi based Examples.

https://learn.adafruit.com/adafruit-magtag/wifi-test

Code: Select all

// Enter your WiFi SSID and password
char ssid[] = "YOUR_SSID";             // your network SSID (name)
char pass[] = "YOUR_SSID_PASSWORD";    // your network password (use for WPA, or use as key for WEP)

User avatar
brubell
Learn User Page
 
Posts: 2017
Joined: Fri Jul 17, 2015 10:33 pm

Re: Scanning for best ssid before connecting to IO

Post by brubell »

Every example program for the AdafruitIO library presumes you know the target WiFi SSID before any code executes. But I would like to first scan for the access point with the strongest WiFi sign
What board are you using?

User avatar
JackTheSE
 
Posts: 54
Joined: Wed Jan 02, 2019 8:34 pm

Re: Scanning for best ssid before connecting to IO

Post by JackTheSE »

I now have a working sketch which accomplishes what I have wanted. Runs fine on various ESP32s I have, including a Feather. The code is in three modules. Here is a listing of the module that scans for, and connects to, the WiFi signal that is strongest and has the correct ssid password:

Code: Select all

extern String ssid;
extern char* password;

int WiFiStat;
int iSSID;

void WiFiInit() {
  Serial.println("WiFi connection initiated");
Rescan:
  do {                                         // loops to scan for SSIDs and then try to connect to each
    WiFiStat = WiFi.status();                  // begin scanning
    WiFi.disconnect();
    WiFi.mode(WIFI_STA);                       // station mode (normal client/server connected device)
    Serial.printf("SSID scan start at %d msec\n", millis());
    int numfound = WiFi.scanNetworks();        // perform scan
    Serial.printf("scan completed at %d msec\n", millis());
    if (numfound <= 0) {                       // true if no SSIDs found
      Serial.println("\nno networks found");
    } else {                                   // true if SSISs found
      Serial.printf("%d SSIDs found\n", numfound); 
      for (int i = 0; i < numfound; ++i) {     // print out found SSIDs (its sorted by dbM)
        Serial.printf("%d. %s (%ddbM)\n", i + 1, WiFi.SSID(i).c_str(), WiFi.RSSI(i));
      }
      iSSID = -1;
      while (iSSID < numfound) {               // try to connect to each found SSID
        iSSID = iSSID + 1;
        Serial.print("\nConnecting to "); Serial.print(WiFi.SSID(iSSID));
        long int WiFiTimer = millis() + 15000; // allow 15 secs for connecting with this SSID
        WiFi.begin(WiFi.SSID(iSSID).c_str(), password);
        while (millis() < WiFiTimer) {         // true if not yet connected
          while (WiFi.status() != WL_CONNECTED) {
            Serial.print(". ");
            delay(1000);
          }
          Serial.printf("\nWiFi connected to %s, (%s)\n", WiFi.SSID(iSSID).c_str(),
                        WiFi.localIP().toString().c_str());
          ssid = WiFi.SSID(iSSID);             // AIO will now use this SSID to reconnect,
          return;
        }
      }
    }
  }
  while (WiFi.status() != WL_CONNECTED);
}
The next module does the AIO connection and reconnection process:

Code: Select all

extern String ssid;
extern char *password;

AdafruitIO_WiFi myio(IO_USER, IO_KEY, ssid.c_str(), password); // Create myio instance

extern int WiFiStat;
int AIOStat = 0;
bool AIOnotConnecting = true;

void AIOStrobe() {           // Possible callback declarations here, if any. Eg:
  WiFiStat = WiFi.status();
  AIOStat = myio.status();
  if (AIOStat == AIO_CONNECTED && AIOnotConnecting) {
    myio.run();
    return;
  }
//  Serial.printf(" %s  %s\n", WiFiStatus(WiFiStat).c_str(), AIOStatus(AIOStat).c_str());
  if (WiFiStat != WL_CONNECTED && AIOnotConnecting) {
    WiFiInit();
    return;
  }
  if (WiFiStat == WL_CONNECTED && AIOnotConnecting) {
    Serial.printf("AIO is Connecting to %s, %s\n", ssid.c_str(), password);
    myio.connect();
    AIOnotConnecting = false;
    return;
  }
  if (AIOStat == AIO_CONNECTED) {
    Serial.println("AIO is connected");
    AIOnotConnecting = true;
//    myTime();
  }
  return;
}
And the last module is the main program:

Code: Select all

//   This sketch assumes ESP32 Dev Module board
#include <AdafruitIO_WiFi.h>
#include "AIO.h"
#define LED_BUILTIN 2          // not defined for Dev Kit!

extern bool AIOisOK;           // true if AIO is taking data

void setup() {
  Serial.begin(9600);          // start the serial connection
  while (!Serial);             // wait for serial monitor to open
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.println("\nBegin AIO in Loop");
  WiFiInit();
}
void loop() {
  AIOStrobe();
}
And I have the following .h file ( that also contains the AIO user and key, omitted):

Code: Select all

String ssid = "Just_A_Filler_Here";
char *password = "my password here";
I test this code by plugging in a wifi extender next to the ESP32, and it first connects to this strong signal. I then unplug the extender, and the sketch detect that wifi is lost (takes about 8 seconds), and then rescans and connects again, then calls myio.connect() which attaches properly to the new ssid.

User avatar
mikeysklar
 
Posts: 14165
Joined: Mon Aug 01, 2016 8:10 pm

Re: Scanning for best ssid before connecting to IO

Post by mikeysklar »

Good work and thanks for sharing your solution.

User avatar
JackTheSE
 
Posts: 54
Joined: Wed Jan 02, 2019 8:34 pm

Re: Scanning for best ssid before connecting to IO

Post by JackTheSE »

thanks. One key learning for me was that I had to actually log in to my ssid before calling myio.connect. That step apparently forces myio.connect to remember the ssid properly.

User avatar
cjdshaw
 
Posts: 59
Joined: Mon May 08, 2017 4:04 pm

Re: Scanning for best ssid before connecting to IO

Post by cjdshaw »

WifiMulti should do what you're trying to achieve - connect to the best of a selection of APs
https://arduino-esp8266.readthedocs.io/ ... mples.html

User avatar
JackTheSE
 
Posts: 54
Joined: Wed Jan 02, 2019 8:34 pm

Re: Scanning for best ssid before connecting to IO

Post by JackTheSE »

WifiMulti should do what you're trying to achieve - connect to the best of a selection of APs
WiFiMulti appears to require knowing a list of valid SSIDs at compile time, but I wanted to cover the case where you don't know any SSIDs at all during compile. I wanted the freedom to change my router SSID, add or take away WAPs or extenders, etc., or even move a battery-powered device to a different house, and I wanted my microcontroller to react to that automatically, and reconnect to both WiFi and AdafruitIO. That's why I scanned for SSIDs if I became disconnected from WiFi.

One further complication is that when io.connect is called from within the loop function, the first thing it does is disconnect from WiFi, and then tries to reconnect, but to what SSID? I tried many ways to deal with all this, and my solution above is the only thing that worked for me.

Locked
Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.

Return to “Internet of Things: Adafruit IO and Wippersnapper”