Photon goes into listening mode after WiFi.setCredentials()

I’m working on setting up a custom behavior to allow setting WiFi credentials through a basic serial terminal. The idea being that credentials will be configured in a WPF application without needing to physically access the buttons on the photon. Instead a cloud function is called to clear a flag on the devices EEPROM that designates that its WiFi has been configured.

The logical process is as follows:

  • Device starts
  • Devices checks EEPROM “flag” to see if WiFi credentials have been set
  • If not, device goes into a function listening over serial input for credentials
  • Once all fields are recieved, device uses WiFi.clearCredentials(), WiFi.setCredentials() and WiFi.connecting() to validate credentials
  • If credentials are validated, EEPROM flag is set to “true” and device resets.

It’s at this point that the device enters listening mode and stays their through complete reboots. This code was working as I had intended a few weeks ago, but now it’s not and I haven’t changed anything that I can recall.

Relevant code below:

void checkEEPROM(){
  int IDAddr = 0;
  int WiFiAddr = 11;
  uint16_t custID;
  uint16_t WiFiCheck;
  EEPROM.get(IDAddr, custID);
  if(custID == 0xFFFF) {
    // Setup ID, TBI
  }
  EEPROM.get(WiFiAddr, WiFiCheck);
  if(WiFiCheck != 0x1337) { //Saving anything but raw hex is causing issues
    setupWiFi();
  }
}

void setupWiFi(){
  WiFi.off();
  WiFi.disconnect();
  getSerialString("WiFi setup initialised. Press Enter to continue.");
  String SSID = getSerialString("Enter Network Name");
  String password = getSerialString("Enter Newtork Password");
  SecurityType auth;
  String authString = getSerialString("Enter Newtork Authentication: WPA2, WPA, WEP");

  if (authString == "WPA") {
    auth = WPA;
  }
  else if (authString == "WEP") {
    auth = WEP;
  }
  else {
    auth = WPA2;
  }

  WiFi.clearCredentials();
  WiFi.setCredentials(SSID, password, auth);
  Serial.println("Credentials Set");

  int timeout = 30;
  while(WiFi.connecting()) {
    if (timeout < 0) {
      Serial.println("Connection Error, device restarting");
      // WiFi.clearCredentials();
      System.reset();
    }
    timeout--;
    delay(1000);
  }

  EEPROM.put(11, 0x1337);
  Serial.println("Connection Established, device restarting");
  System.reset();
}

String getSerialString(String prompt) {
  size_t READ_BUF_SIZE = 64;
  unsigned long CHAR_TIMEOUT = 30000;

  // Global variables
  char readBuf[READ_BUF_SIZE];
  size_t readBufOffset = 0;
  unsigned long lastCharTime = 0;


  Serial.println(prompt);
  while(true){
    while(Serial.available()) {
  		if (readBufOffset < READ_BUF_SIZE) {
  			char c = Serial.read();
  			if (c != '\n') {
  				// Add character to buffer
  				readBuf[readBufOffset++] = c;
  				lastCharTime = millis();
  			}
  			else {
  				// End of line character found, process line
  				readBuf[readBufOffset] = 0;
  				Serial.printlnf("got: %s", readBuf);
  				readBufOffset = 0;
          return readBuf;
  			}
  		}
  		else {
  			Serial.println("readBuf overflow, emptying buffer");
  			readBufOffset = 0;
  		}
  	}
  	if (millis() - lastCharTime >= CHAR_TIMEOUT) {
  		lastCharTime = millis();
  		readBuf[readBufOffset] = 0;
  		Serial.printlnf("got timeout: %s", readBuf);
  		readBufOffset = 0;
      Serial.println(prompt);
  	}
  }
}

There are some logical mistakes in your code

  • WiFi.off() before WiFI.disconnect() doesn’t make sense. Once the WiFi module is off, there is no way it could still be connected, hence WiFi.disconnect() is superfluous
  • with the WiFi module being off, neither WiFi.clearCredentials() nor WiFi.setCredentials() are supposed to work. You first need to call WiFi.on() again.
  • the three parameter WiFi.setCredentials() overload only works on present and visible networks - otherwise you’d need the four-parameter overload which also takes the WLAN_CIPHER
  • you don’t seem to call WiFi.connect() after setting credentials hence WiFi.connecting() won’t ever become true
  • you are using your WiFiAddr variable for EEPROM.get() but use literal 11 for EEPROM.put() - this might cause possible issues when reworking the code.

Additional hints:

  • it might not be necessary, but I’ve made it a habit to call WiFi.off(); delay(100); WiFi.on() between clearing and setting credentials.
  • I’d use SYSTEM_MODE(SEMI_AUTOMATIC) (or MANUAL) and `SYSTEM_THREAD(ENABLED)

I’m not sure where this comment comes from

I’ve never had any issues storing complete structs to EEPROM or reading structs and strings from it.

3 Likes

Not sure how I missed that in the documentation, or why it was working before, but that fixed the issue.

I wasn’t worried about hidden network at the time I wrote this, but adding it in worked fine.

1 Like

So I’ve gotten the time to do some more testing on this and have found that the solution provided only gives half of the functionality I need. (Relevant functions)

When the WiFi credentials are entered correctly, everything works fine, except I don’t seem to get a “Connection Established” message anymore. But when incorrect credentials are given I’ll get the “Credentials Set” message and then the device immediately goes into listening mode.

I tried the off, delay, on routine suggested by @ScruffR but that caused any credentials entered to fail, causing the device to enter listening mode for ~1 minute, before restarting and entering setupWiFi()