hasCredentials() always returns false unless .connect() has been called

opps. :wink: but anyways, the code above works with an empty factory reset core.

Tested and working for sure.

My understanding of the original question was for the opposite of this - to not enter listening mode but rather simply not connect so that the “not connected and no credentials” status can be displayed.

So should it be simply changing what’s in the loop (now containing WiFi.listen()?

if (WiFi.tryConnect() == WIFI_NO_CREDENTIALS) {

  // user code to toggle external LED to indicate credentials are needed
  WiFi.listen();
}

VS

SYSTEM_MODE(SEMI_AUTOMATIC);

void setup(){
  if(!WiFi.hasCredentials()){
   //light up led
    WiFi.listen();
  }
}

maybe something like this?

void setup(){
  if(!WiFi.hasCredentials()){
      // set LED to indicate no credentials
  } else {
      WiFi.connect();
  }
}
2 Likes

@mdma This is exactly what I’ve tried, but my observation is that hasCredentials() will ALWAYS RETURN FALSE regardless of whether you have credentials stored or not UNTIL WiFi.connect() has been called.

To put it differently, this code will ALWAYS trigger listen mode:

SYSTEM_MODE(SEMI_AUTOMATIC);

void setup(){
  if(!WiFi.hasCredentials()){
   //light up led
    WiFi.listen();
  }
}

but this code will work correctly:

SYSTEM_MODE(SEMI_AUTOMATIC);

void setup(){
  WiFi.connect();
  WiFi.disconnect();
  if(!WiFi.hasCredentials()){
   //light up led
    WiFi.listen();
  }
}

Except of course it would not, if you didn’t have credentials stored, because .connect() will put it in listening mode, so it will block until credentials are supplied via USB or Smart Config App.

The reason it @mdma 's code does not work is because hasCredentials() internally checks the value of a data structure that’s not been properly initialized:

https://github.com/spark/firmware/blob/master/src/spark_wiring_wifi.cpp#L348

Here: NVMEM_Spark_File_Data[WLAN_PROFILE_FILE_OFFSET] != 0 will always be 0 until it’s populated during .connect() method:

https://github.com/spark/firmware/blob/master/src/spark_wiring_wifi.cpp#L148

I suspect that the reason for this is that you need to start the wlan chip first to be able to query it for the stored credentials, and it would not make sense to start it until we want to use it (for power consumption reasons, etc.)

Do you see the problem now?

Thanks!
Alexander

2 Likes

Why don’t you post your code? I don’t get your point and don’t think those that you mentioned are causing some issue.

It also depends on how you are testing it to figure out if it works or if it does not.

You are saying that you want your television to remain off while being able to browse through the channel. How is that possible?

The CC3000 needs to be powered on in order to communicate. With that, I don’t mean executing WiFi.connect()

Thanks for that explanation @akiesels, now I get it! I think we can fix this one pretty quickly - the solution is to try to populate the NVMEM variable in SPARK_WLAN_Setup() which is called to initialize the cc3000. Then they will be available for use for testing if there are any credentials.

https://github.com/spark/firmware/blob/master/src/spark_wlan.cpp#L378

Just after Delay(100) add

nvmem_read(NVMEM_SPARK_FILE_ID, NVMEM_SPARK_FILE_SIZE, 0, NVMEM_Spark_File_Data);

That will ensure the NVMEM_Spark_File_Data is initialized without needing to call WiFi.connect();

Would be great if you could try this out and submit a PR if it works!

3 Likes

Thanks @mdma. Just got around to trying your fix. Compiles ok, but when I flash the core it comes up and immediately throws a flashing red “SOS” message. Removed the line - everything peachy (except that hasCredentials is false before connect, of course). Here is my code to try it out, btw:

SYSTEM_MODE(SEMI_AUTOMATIC);
void setup()
{
	pinMode(D0, OUTPUT);  // RED LED attached here
	pinMode(D1, OUTPUT);  // BLUE LED attached here

	if (WiFi.hasCredentials()) {
		digitalWrite(D0, LOW);
		digitalWrite(D1, HIGH);
	}
	else {
		digitalWrite(D0, HIGH);
		digitalWrite(D1, LOW);
	}

	WiFi.connect();

	if (WiFi.hasCredentials()) {
		digitalWrite(D0, LOW);
		digitalWrite(D1, HIGH);
	}
	else {
		digitalWrite(D0, HIGH);
		digitalWrite(D1, LOW);
	}
}

I’ve got a red LED connected to D0 and a blue LED to D1 (each through a 220 ohm resistor). When the core boots, the RED LED comes on first and once the WiFi is connected, it goes off and the BLUE one lights up. Since I have the credentials stored, I should only ever see the BLUE one light up.

So, what’s causing it to crash running that nvmem_read code on line 378? Maybe CC3000 is not quite ready after the 100ms delay? I doubt it, though, as I tried upping it to 1000ms and it still causes the same red SOS (except now I can catch a glimpse of solid white on the core LED when it first boots).

Any other suggestions I can try?

Thanks,
Alexander

1 Like

P.S. Tried adding wlan_start(0) right after delay(100) and before calling nvmem_read. Works correctly now - no crash and only the BLUE LED lights up.

But do we want to call wlan_start(0) at this point? What if I want to keep the wlan off for a while for power consumption reasons? I suppose we could add logic to hasCredentials to check to see if wlan has been started and if not, start it a run nvmem_read then? Otherwise, use the current flag-based implementation.

Your thoughts?

Ah, my mistake - I thought wlan_start(0) was already called. That was my intent.
(I’m working with a different version of the code, so confusing new/old code.)

You can try putting the nvmem read inside WiFi::on(), after the wlan_start(0) that’s there, and call Wifi::on() in your setup() function. That should fix it! :slight_smile:

2 Likes

Thanks Matthew! Are you guys working on refactoring this code already? I found some more issues with the way connection states are evaluated. E.g. calling WiFi.on() will toggle WiFi.connecting() state, even though you’re not actually connecting, or similarly, calling WiFi.connect() and then later WiFi.disconnect() will also make WiFi.connecting() evaluate to true - again incorrect. There are others, like the inability to programmatically detect wrong wifi credentials (the infinite flashing green LED problem). I am happy to help with this, if I can, since I will have to make it work for my specific application, but if these are all known issues and fixes are in the works, then I will focus my energy elsewhere :smile:

Thanks again,
Alexander

1 Like

I’ve refactored the code, but not changed how it functions. Please feel free to open a github issue with your findings so we have a place to discuss the issues and potential fixes!

Hi again @akiesels!

I just pushed a fix for this issue to the feature/hal branch on the firmware repo. If you are building locally, please take it for a spin!

The state problems with WiFi I believe have been addressed, but to be sure, if you have any test code, please let me have it so I can plug that into our integration tests so that we know it’s fixed for sure!

For programmatically detecting wrong credentials, there’s an app issue for that! https://github.com/spark/firmware/issues/359

Cheers,
mat.

Hi @mdma,

I missed this post earlier somehow - sorry about that! So, I just pulled the latest source from the feature/hal branch, built it locally and flashed the core over USB. My test application code is very simple, same as the one in the original post above.

Unfortunately, I am still seeing incorrect behavior with the new firmware:

If the core has credentials stored, upon restart the red LED connected to D0 comes on and stay lit until wifi connection is made. At which point the blue LED connected to D1 lights up and the red one on D0 goes off.

So, it looks like .hasCredentials() is still returning false until wifi connection is made, regardless of whether credentials are actually stored or not.

Let me know if I can help troubleshoot this further.

Thanks,
Alexander

Hi @akiesels and @mdma

I am seeing the same issue here. I am trying to handle network association manually in my code just for experimentation. The following code loops forever even though the smart config app is running on my android transmitting settings. It seems WiFi.hasCredentials() always returns false in my code. This seems to be related to the issue in this post.

Here is the code snippet(module is in SYSTEM_MODE(SEMI_AUTOMATIC):

void setup()
{
	Serial.begin(9600);
	delay(1000);
	Serial.println("Start");
	WiFi.on();

	retry:

	if(!WiFi.hasCredentials()){
		Serial.println("No WiFi Credentials starting listen");
		WiFi.listen();
		while(!WiFi.hasCredentials());
		Serial.println("Got Credentials");
	}
	Serial.println("Connecting");
	WiFi.connect();
	Serial.println("Connecting WiFi");

	unsigned long startTime = millis();

	while(!WiFi.ready() || millis() < startTime + connectTimeout){
	}
	if(!WiFi.ready()){
		goto retry;
	}
	Serial.println("WiFi Connected");
}

The RGB LED turns on Blue at boot up and stays on solid indefinitely. Does not flash, just on solid.

Hi @mdma

Is this thread dead? I am back to this issue again with my application. Any fixes yet? I see this problem is not marked solved yet.

Thank you

Are you compiling locally with the feature/hal branch?

Hi @mdma,

Yes I am compiling locally through Eclipse. The problem is I get errors when opening the spark_wlan file right now. Is this where modifications are required? If so what modifications do I need to make?

Thanks,
Travis

@mdma, I can confirm that the light is still solid blue in both the develop and the feature/hal branches. I changed the line:

while(!WiFi.hasCredentials());
to
while(WiFi.listening());

but, to no avail. I am trying to find the relevant lines using the debugger right now…

I was having this problem recently, and wanted to pass on a workaround I found. You can call WiFi.connect with the WIFI_CONNECT_SKIP_LISTEN flag to tell it not to put it into listening mode, e.g.

WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);

I call this right after I call WiFi.on, and then can test for credentials successfully using WiFi.hasCredentials(). Hopefully this helps anyone still fighting with this issue and looking for a workaround. (As this doesn’t contribute directly to the problem, if there’s a more appropriate place for this comment, let me know and I’ll move it).

2 Likes