Skip to content

Feat support for Enterprise WiFi#250

Merged
nitin710 merged 11 commits intomasterfrom
feat-espEnterpriseWiFi
Mar 31, 2023
Merged

Feat support for Enterprise WiFi#250
nitin710 merged 11 commits intomasterfrom
feat-espEnterpriseWiFi

Conversation

@nitin710
Copy link
Collaborator

@nitin710 nitin710 commented Mar 8, 2023

Description

  • Adds support to connect to Enterprise WiFi networks on Feather ESP32.

Requirements

  • None

Issues Referenced

Functionality

  • The user has an option to add enterprise WiFi credentials to the SD-Card. The Enterprise WiFi details required are:
    • ssid - Network name you are trying to connect to
    • userid - Your userId. (this may be your university ID. You may need to talk to your university network admin to get these details.
    • username - oftentimes just a repeat of the userid unless specified by your network admin
    • password - Your password associated with your user id.
  • Note: It is necessary to provide the ssid, password and userid to connect to a network. If the username is not provided, then userid is used as the username. (in the current implementation)
  • To use, add the following segment to the config file with the required details:
    {
      "ssid": "enterprise-1",
      "userid": "user1",
      "username": "user1_name",
      "password": "prize1"
    },

Documentation update

Testing

Test Configuration:

  • Firmware version: 1.5.4.feat-espEnterpriseWiFi.0
  • Hardware: EmotiBit v5 and EmotiBit v4
  • Using the following config file to test different cases for Enterprise WiFi
{
  "WifiCredentials": [
    {
      "ssid": "personal-1",
      "password": "pass1"
    },
    {
      "ssid": "personal-2",
      "password": "pass2"
    },
    {
      "ssid": "enterprise-1",
      "userid": "user1_id",
      "username": "user1_name",
      "password": "prize1"
    },
    {
      "ssid": "enterprise-2",
      "userid": "user2",
      "password": "prize2"
    }
  ]
}

Testing Results

  • Feather ESP32 ✔️
Attempting to connect to SSID: personal-1
[ 16379][V][WiFiGeneric.cpp:96] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
WiFi.begin() duration = 23
WiFi.status() = 6, total duration = 624
<<<<<<< Switching WiFi Networks >>>>>>>
[ 18451][V][WiFiGeneric.cpp:300] _arduino_event_cb(): STA Disconnected: SSID: personal-1, BSSID: 00:00:00:00:00:00, Reason: 201
[ 18452][D][WiFiGeneric.cpp:852] _eventCallback(): Arduino Event: 5 - STA_DISCONNECTED
[ 18453][W][WiFiGeneric.cpp:873] _eventCallback(): Reason: 201 - NO_AP_FOUND
[ 18453][D][WiFiGeneric.cpp:889] _eventCallback(): WiFi Reconnect Running
[ 18457][V][WiFiGeneric.cpp:96] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
Attempting to connect to SSID: personal-2
[ 18551][V][WiFiGeneric.cpp:96] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
WiFi.begin() duration = 70
WiFi.status() = 1, total duration = 670
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: enterprise-1
trying enterprise WiFi: -SSID: enterprise-1 -userid: user1_id -username: user1_name -pass: prize1
[ 19234][V][WiFiGeneric.cpp:96] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
WiFi.begin() duration = 82
WiFi.status() = 1, total duration = 683
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: enterprise-2
trying enterprise WiFi: -SSID: enterprise-2 -userid: user2 -username: user2 -pass: prize2
  • Feather M0 ✔️
Attempting to connect to SSID: personal-1
WiFi.begin() duration = 952
WiFi.status() = 6, total duration = 1553
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: personal-2
WiFi.begin() duration = 921
WiFi.status() = 6, total duration = 1521
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: enterprise-1
Skipping Enterprise SSID: enterprise-1
Enterprise WiFi is supported only for ESP32
WiFi.begin() duration = 1
WiFi.status() = 6, total duration = 601
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: enterprise-2
Skipping Enterprise SSID: enterprise-2
Enterprise WiFi is supported only for ESP32
WiFi.begin() duration = 0
WiFi.status() = 6, total duration = 600
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: personal-1

Binaries for testing

Checklist to allow merge

  • All dependent repositories used were on branch master
  • Software
    • Passed testing on Windows
    • Passed testing on macOS
    • Passed testing on linux (ubuntu)
  • Firmware
    • Set testingMode to TestingMode::NONE
    • Set const bool DIGITAL_WRITE_DEBUG = false (if set true while testing)
    • Update version in EmotiBit.h
    • Update library.properties to the correct version (should match EmotiBit.h)
  • Update software bundle version in ofxEmotiBitVersion.h
  • doxygen style comments included for new code snippets
  • Required documentation udpated

Screenshots:

@produceconsumerobot
Copy link
Collaborator

produceconsumerobot commented Mar 15, 2023

Testing this on Huzzah32 at the UNR Innevation center on UNR-EXT failed with the following behavior:

<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: UNR-EXT
trying enterprise WiFi: -SSID:UNR-EXT -userid:**** -username:**** -pass:****
[942915][V][WiFiGeneric.cpp:96] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
WiFi.begin() duration = 130
WiFi.status() = 4, total duration = 730
<<<<<<< Switching WiFi Networks >>>>>>>
Attempting to connect to SSID: GalaxyBot7
[944623][V][WiFiGeneric.cpp:300] _arduino_event_cb(): STA Disconnected: SSID: UNR-EXT, BSSID: 04:bd:88:69:6d:a2, Reason: 202
[944624][D][WiFiGeneric.cpp:852] _eventCallback(): Arduino Event: 5 - STA_DISCONNECTED
[944624][W][WiFiGeneric.cpp:873] _eventCallback(): Reason: 202 - AUTH_FAIL

Switching to Examples>WiFi>WiFiClientEnterprise.ino initially fails to connect with WiFi.begin(), times-out, and calls ESP.restart(). After restart WiFi.begin() works. Changing the timeout from 30 seconds to 3 seconds works. 2 seconds did not work.

Using this code also did not work:

WiFi.disconnect(true);      
esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_ID, strlen(EAP_ID));
esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_USERNAME, strlen(EAP_USERNAME));
esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD));
esp_wifi_sta_wpa2_ent_enable();
// WPA2 enterprise magic ends here
WiFi.begin(ssid);

Utilizing ESP.restart() is too janky to include in our firmware, so until we have more time to dig deeper into why it isn't working and figure out if there is a way to fix it gracefully, this PR and enterprise WiFi will unfortunately have to be ice-boxed.

@produceconsumerobot
Copy link
Collaborator

produceconsumerobot commented Mar 16, 2023

With the following code inside EmotiBitWifi.cpp and a long (>10sec) attemptDelay ESP32 will connect to UNR-EXT enterprise wifi.

    WiFi.disconnect(true);      
    WiFi.mode(WIFI_STA); //init wifi mode
    esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)credential.userid.c_str(), credential.userid.length());
    esp_wifi_sta_wpa2_ent_set_username((uint8_t *)username.c_str(), username.length());
    esp_wifi_sta_wpa2_ent_set_password((uint8_t *)credential.pass.c_str(), credential.pass.length());
    esp_wifi_sta_wpa2_ent_enable();
    wifiStatus = WiFi.begin(credential.ssid.c_str());

However, EmotiBit data is not presently visible in the oscilloscope for an unknown reason -- could be the router is filtering our unicasts, but not sure.

Needs to be tested if our auto-reconnect with 100msec attemptDelay will work after dropping the connection. May need to increase WIFI_BEGIN_ATTEMPT_DELAY to >10sec.

@produceconsumerobot
Copy link
Collaborator

produceconsumerobot commented Mar 17, 2023

2 new problems:

  1. Original Feather with EmotiBit FW was not pingable at it's IP (192.168.226.33) until it was programmed with the enterprise wifi example code (below) and then it was pingable and showed up in Colosoft MAC Scanner. After reprogramming with the EmotiBit FW it continued to be pingable and showed up in MAC Scanner and streamed data in the oscilloscope. It seems possible that ESP.restart() was necessary to clear some garbage. It may be possible to figure out a way to implement ESP.restart(), but it's a tad ugly given that the Feather thought everything was hunky dory.

WiFi.disconnect(true); //disconnect form wifi to set new wifi connection
WiFi.mode(WIFI_STA); //init wifi mode

// Example1 (most common): a cert-file-free eduroam with PEAP (or TTLS)
WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_IDENTITY, EAP_USERNAME, EAP_PASSWORD);>

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
counter++;
if(counter>=60){ //after 30 seconds timeout - reset board
ESP.restart();
}
}

  1. Programming a second Feather with the enterprise wifi example worked to ping the device BUT it was assigned to a different subnet (192.168.227.12) than my computer (and the other Feather). The Feather was pingable, but did not show up in MAC Scanner or the Oscilloscope. It's not entirely clear how to solve this problem without spamming 255x255 device IPs (255.255.0.0 mask). This may be the death knell for this PR until a new solution presents itself. Spamming 255x255 devices at 1/msec would take 65 seconds, likely trigger spam filters, and we would need to refactor EmotiBitWiFiHost to support multiple EmotiBits on different networks, which all sounds not super bueno. It's possible we would want to refactor EmotiBitWiFiHost.cpp to have networkIncludeList include work differently so that it didn't do an && with XXX.XXX.XXX.* of subnets the computer is attached to.

image

Closing PR as too difficult to accomplish in the near future.

@nitin710 nitin710 reopened this Mar 29, 2023
…p. Moved WiFi.disconnect out of enterprise wifi cred. conditional
@nitin710
Copy link
Collaborator Author

Added software restart provision.
Press R before setup starts to software reset the Feather.
You may use the following compiled binaries for testing. @produceconsumerobot
1.5.4.feat-espEnterpriseWiFi.1.zip

Copy link
Collaborator

@produceconsumerobot produceconsumerobot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review 01

// ToDo: There is no catch right now for timeout. In case of timeout, EmotiBit still continues to complete setup() and proceed to update()
_emotiBitWiFi.begin(-1, 1);
_emotiBitWiFi.begin(-1, 1, 20000);
led.setLED(uint8_t(EmotiBit::Led::BLUE), false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be value to adding the following code to (1) self-heal enterprise gunkiness (2) prevent confusion of entering the main loop before a connection is established?
if (_emotiBitWiFi.status() != WL_CONNECTED)
{ restart }

Does it create any problems/risks?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps:
attemptDelay = 20000; // ESP32 has been observed to take >10 seconds to resolve an enterprise connection
maxAttemptsPerCred = 1;
timeout = attemptDelay * maxAttemptsPerCred * _emotibitWifi.getNumCredentials() * 2; // Try cycling through all credentials at least 2x before giving up and trying a restart
_emotiBitWiFi.begin(timeout, maxAttemptsPerCred, attemptDelay );
if (!connected) {restart}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current behavior is to try and connect to a network in an infinite loop.
I think this change keep the behavior the same, i.e., an infinite connect loop in setup, AND also improves it by providing a software reset.
Also, agreed that it will help with enterprise WiFi too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this change

Copy link
Collaborator Author

@nitin710 nitin710 Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On testing, i notice that if a user only adds 1 credential, and it happens to be the wrong one, then the Emotibit will restart every 40secs.

Since the EmotiBit will be cycling through setup states, we might want to consider possible UX issues

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per discussion, added the required change.
New behavior:
If enterprise network is listed in the credential list, then a timeout (As calculated above) will be used before MCU is restarted.
If no enterprise network is listed, then there will be no timeout and the emotibit will keep trying to connect to listed networks.

credentials[numCredentials].ssid = ssid;
credentials[numCredentials].pass = password;
credentials[numCredentials].userid = userid;
credentials[numCredentials].username = username;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a conditional here to print an error and return -1 when numCredentials >= MAX_CREDENTIALS

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. The code now handles passing MAX_ALLOWED number as shown below (with a simulated limit of 1)

Loading configuration file: config.txt
Number of network credentials found in config file: 4
Adding SSID: personal-1 -pass:pass1... success
Adding SSID: personal-2 -pass:pass2...failed to add credential
***Credential storage capacity exceeded***
Ignoring credentials beginning: personal-2

EmotiBitWiFi.cpp Outdated
_needsAdvertisingBegin = true;
while((wifiStatus == WL_IDLE_STATUS) && (millis() - beginDuration < attemptDelay)); // This is necessary for ESP32 unless callback is utilized
//while((wifiStatus == WL_IDLE_STATUS) && (millis() - beginDuration < attemptDelay)) // This is necessary for ESP32 unless callback is utilized
while((wifiStatus != WL_CONNECTED) && (millis() - beginDuration < attemptDelay)) // This is necessary for ESP32 unless callback is utilized
Copy link
Collaborator Author

@nitin710 nitin710 Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ESP was not waiting for the full 20 secs (set as attemptDelay)
Snippet from serial monitor:

Attempting to connect to SSID: personal-1
WiFi.begin() duration = 134
attemptDelay: 20000  -  WiFi.status() = 6  // Wifi status == WL_DISCONNECTED
attemptDelay: 20000  -  WiFi.status() = 1  // WiFi status changes to WL_NO_SSID_AVAIL
WiFi.status() = 1, total duration = 4136   // This WL status makes it jump out of the while(wait for attempDelay) before 20secs

Therefore, the conditional in the while has been changed to make sure the MCU waits for attemptDelay seconds before moving on.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nitin710 why would we want to wait 20 seconds if WL_NO_SSID_AVAIL?

Copy link
Collaborator Author

@nitin710 nitin710 Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to move on faster i guess.
Change has been undone.
Now ESP moves on to the next SSID if network is not available.

EmotiBitWiFi.cpp Outdated
_needsAdvertisingBegin = true;
while((wifiStatus == WL_IDLE_STATUS) && (millis() - beginDuration < attemptDelay)); // This is necessary for ESP32 unless callback is utilized
//while((wifiStatus == WL_IDLE_STATUS) && (millis() - beginDuration < attemptDelay)) // This is necessary for ESP32 unless callback is utilized
while((wifiStatus != WL_CONNECTED) && (millis() - beginDuration < attemptDelay)) // This is necessary for ESP32 unless callback is utilized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nitin710 why would we want to wait 20 seconds if WL_NO_SSID_AVAIL?

@nitin710 nitin710 merged commit 2c7cc6f into master Mar 31, 2023
@nitin710 nitin710 deleted the feat-espEnterpriseWiFi branch October 16, 2025 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feather is unable to connect to UNR-IOT network

2 participants