Is testing for "active" in imp.net.info() a satisfactory proxy for server.isconnected()

Initially, I’d looked at:

if (server.isconnected()) {
  local info=imp.net.info()
  ...
}

or

local info=imp.net.info()
if (server.isconnected()) {
  ...
}

but I become concerned that the connection state machine could change in between instructions. Can I instead rely on the following test as functionally the same as server.isconnected()?

local info=imp.net.info()
if ("active" in info) {
  // all data in info will reflect that the device is connected to the server...
  ...
}

Yes they both make the same underlying query on the network stream.

I’ll add a note in the Dev Center API docs about this.

This isn’t working as well as I expected. I have test devices relying on the test (“active” in imp.net.info()) for me to be confident that the wifi interface slots are populated. This code below is failing occasionally with a runtime error, stating that the index “bssid” doesn’t exist. Please note that I am testing that the active interface is wifi before assuming that the bssid field is there. I can always test for the presence of bssid as well, but I thought it would be unnecessary.

  local info = imp.net.info()
  if ("active" in info) {
                    
    if (!server.isconnected()) {
      debug.write("SERIOUS ERROR, SERVER NOT CONNECTED!!!")  // this is never called
    }
                    
    _interface = info.interface[info.active]  // retain snapshot of current active state
                    
    if (_interface.type=="wifi" && _interface.bssid=="000000000000") 
      disconnect(KEY_WIFI_DISCONNECT) // lost contact with base station
  }
  else 
    // connection has been lost, force early disconnection
    disconnect(KEY_UNEXPECTED_DISCONNECT)

Thinking about this, perhaps "active" in imp.net.info() shouldn’t be used as or considered a proxy for server.isconnected() since active should indicate which interface is currently ‘selected’, but ‘selected’ is not the same thing as ‘connected’. That’s clearly what’s happening here: wifi is the selected (active) interface but is not connected (which is why the bssid key is missing).

I guess, @coverdriven, you’re back to checking server.connected() first, or checking for "bssid" in _interface.

Although, you do see that I check for server.isconnected() above and it always returns true, thus making it useless in this scenario too. I think the documentation needs to be updated to say that you must test for everything before referencing, nothing is certain. :confused:

On a more serious note, this is slightly problematic with a language like Squirrel, which raises an exception in these situations. Javascript would return undefined and continue running. Even though a try/catch caught the exception further up the call stack, execution of any of the immediate code after the bssid reference was skipped. Hard to plan for that.

I’m being pedantic, but we are talking about rock-solid embedded devices against ones that only sail in fair weather.

When you get a missing bssid, do you dump the rest of the table?

Looking in the code, WiFi interfaces only populate some fields when associated - essentially, we try to read the WiFi interface’s RSSI and if this is zero (implying that the interface is not yet associated, or on the way to being disassociated) then the rssi, bssid and connectedssid fields are not created.

I’m slightly surprised that you’re seeing server.connected() being true when not associated, but both active and server.connected refer to the TLS stream; I suspect WiFi can return a zero RSSI before it raises a link error and in that case you’d see this happen because until the link error is raised, the TLS link is assumed to be up.

At the point you see the trouble, are you doing scanning/reselection of WiFi networks?

To answer Hugo’s questions.

When I get a missing bssid, I get a runtime error, because I didn’t expect it. I’m now coding around that.

At the point that I see the trouble, the device is still reporting as connected (server.isconnected() is true, (“active” in imp.net.info()) is true). However, the onunexpecteddisconnection() event is still up to 60s away.

I think I know what is happening here.

Back when I was using imp.getbssid(), it would either return the bssid, or 12 zeroes to indicate that it had lost contact with the base station. The zeros could happen even when server.connected() still returned true. This is an early warning that the connection was about to be lost. I assumed that I should look for 12 zeroes when inspecting the wifi interface returned from imp.net.info(). Instead, the bssid field is simply not there. This can still happen (if only for a brief moment) when server.isconnected() is still true and even when an active interface is still reported.