Swapping wifi credentials, imp.getssid <-> imp.getbssid, workaround

Hello,

I know this discussion has been around, and opinions stated for various reasons. I recently have found that determining the current connected network very tedious, and prone to issues. Let me explain…

I am creating features for a device that allows it to switch to a backup hotspot when there is a connection error for critical messages, not for “normal” messages (poll, etc). I have read, and understand, the API documentation for the imp.setwificonfiguration() and the imp.getssid() calls.

imp.getssid() return the currently “programmed” credentials the imp will look for upon next connect. I get that.

The issue I have is, I can’t believe how hard it is to determine the current connected network. I made a work around, where I call the imp.getbssid() (which if I understand right does display the currently connected network bssid) and compare that to a hard-coded table where the bssid is also stored. This has to be done after connecting, and requires a build to get that data from a certain network.

The issue with referencing the bssid is that:

  1. You have to know this ahead of time before deploying code to devices in field
  2. Does not take into account a large network with multiple routers (assuming the bssid is different for each router). The credentials can be the same, but the bssid will not be.
  3. Not sure when the bssid is updated in the imp (5 seconds after disconnect, etc).

To explain further, I am using some simple code to swap wifi credentials between a default and backup. Try default first, and if fail, go to backup, when completed set back to default (even though it may not be able to connect).

It seems to me that it would be helpful for the device to store not only the ssid and pw from blinkup (or code), but also the bssid from the last known successful connection (once it connects, stores this so it can be referenced later over cold boot). After a while I came up with these functions (complicated, I know):

`local connections = [
{ ssid = "DEFAULT_SSID, pw = “DEFAULT_PW”, bssid = “XXXXXXXXXXXX”},
{ ssid = “BACKUP_SSID”, pw = “BACKUP_PW”, bssid = “YYYYYYYYYYYY” }];

function reconnect() {
// callback doesn’t matter, if we go to sleep while alwaysOn, this
// will continue trying to connect
server.connect(function(reason) {
if (reason != SERVER_CONNECTED) {
//try again
imp.wakeup(3, reconnect);
} else if (reason == SERVER_CONNECTED) {
if (imp.getbssid() == connections[0].bssid) {
Logger.info("Currently connected to WIFI SSID: " + connections[0].ssid);
} else {
Logger.info("Currently connected to WIFI SSID: " + connections[1].ssid);
}
}
}, TIMEOUT_WIFI);
//server.log(“line 2295”);
}

local swapTimer = null;
local altCount = 0;
local swapSpacing = 10;
local resetWifiTimer = null;
local conn = true;

function swapWIFI() {
if (imp.getbssid() == “000000000000”) {
if (conn) {
imp.setwificonfiguration(connections[1].ssid, connections[1].pw);
altCount +=1;
conn = false;
} else {
imp.setwificonfiguration(connections[0].ssid, connections[0].pw);
altCount +=1;
conn = true;
}
swapTimer = imp.wakeup(swapSpacing, swapWIFI);
} else {
Logger.info(“Alternated WIFI credentials " + altCount + " times”);
altCount = 0;
conn = false;
if (imp.getbssid() == connections[0].bssid && imp.getbssid != “000000000000”) {
Logger.info("Currently connected to WIFI SSID: " + connections[0].ssid);
imp.setwificonfiguration(connections[0].ssid, connections[0].pw); // this is to make sure the “set” credentials are really the current ones
Logger.info("SSID currently set for " + imp.getssid());
} else if (imp.getbssid() == connections[1].bssid && imp.getbssid != “000000000000”){
Logger.info("Currently connected to WIFI SSID: " + connections[1].ssid);
imp.setwificonfiguration(connections[1].ssid, connections[1].pw); // this is to make sure the “set” credentials are really the current ones
Logger.info("SSID currently set for " + imp.getssid());
}
}
}

function resetWIFI() {
if (imp.getbssid() == connections[1].bssid) {
imp.setwificonfiguration(connections[0].ssid, connections[0].pw);
resetWifiTimer = imp.wakeup(15, function() {
server.log("Resetting WIFI back to default: " + connections[0].ssid);
server.flush(30);
server.disconnect();
reconnect();
})
} else if (imp.getbssid() == connections[0].bssid) {
server.log("WIFI connected to defualt: " + connections[0].ssid);
} else if (imp.getbssid() == “000000000000”) {
reconnect();
}
}`

I used the conn variable so I could set the function to always try default the first time round swapping… The 15 sec wakup was to let any actions or firmware through before disconnecting. I would call swapWIFI when there is a connection error (onunexpecteddisconnect) and resetWIFI when the operation was done and the device in a normal state. This kinda works, but requires that the bssid be known, and that it doesn’t change.

For imp003 and above, flash is necessary, so is it possible to have the imp auto store credentials in the system allocation? I really would just like to make a call and get the connected network without all these functions…

Thanks!

I think that there are a number of imp projects where swapping ssids has been supported. In all cases, you really need to have some sort of non-volatile storage for the wifi credentials. It would be useful to preserve the blinkup credentials, but still be able to swap them out temporarily.

As far as I know, there is no functionality to selectively white-list or black-list bssids. I monitor and record bssid changes while my imps operate in multi-AP networks. I’ve asked for an event trigger that will be called when the bssid changes. There are still some weaknesses. If there are multiple APs with the same ssid (different bssids) AND the strongest signal is coming from an AP that isn’t permitting the imp to get a server connection, you are royally stuffed. The imp will always connect to that one.

We do have a config page, and we’ve talked internally about how we offer some of this for end user use; that’d likely be a good place to keep this type of storage. 003’s and later have hardware.spiflash, but a managed atom store would be nice.

Would, for example, 4k be enough for most people?

Surely you don’t need to know the BSSIDs in advance – you can just get it when you first connect to each network?

Peter

@peter - Yes, of course. But what about the situations where imp.getssid does not match its bssid (when swapping the wificonfig)? If I set the wificonfig to something, then call server.connect, if it is already connected it won’t do anything besides run the callback. Then the imp.getssid return the “wrong” setup. Of course, programming, like you said, can solve this by storing bssid on connect. But, it would be nice if the connection manager was expanded to include a “credential manager”, where all the storing and recalling of bssid’s and ssid’s was handled by awesome, robust, and efficient code like the type EI publishes :). What I am trying to get at is yes, programming could handle all this, but for programmers entering the EI arena (and those focused on certain development areas) this is just more headache and time needed to get a simple return of the connected network.

@Hugo - Yes, utilizing that config page would be useful, and the 4k sound good for me. What about expanding the imp.getssid call to return both the next connect ssid (current) and the ssid which has the matching bssid found by calling imp.getbssid? I think it would streamline the connection management process for most people if the imp itself could save the bssid of the successful connection to the ssid that was called. That is, of course, using the calls available in the API as of now. The only “true” way of knowing the connected network is to call imp.getbssid and reference that to the one stored by someone’s clever programming (and storage [device and/or agent]). imp.getcurrentnetwork, for example, would eliminate these issues if it returned the network it is currently connected to (ssid and bssid [bssid of course is from the imp storing it on successful connect]).

And as coverdriven points out, the inability to manage connections based on bssid and rssi parameters is a shortcoming as well. I’m sure EI has plans to account for these types of connection issues. I just wanted to show how cumbersome (and inefficient) it is to manage wifi currently… The Connection Manager class is awesome btw, but extending (or cloning) this type of functional management for credentials would benefit everyone :).

@Hugo
Is that 4KB or 4kbits? 4KB is plenty, 4kbits is probably ok too.

Are you also saying that this would be available in imp002s?

Yes, it’d be available for all imps.

@physicsnole there are extensions to the network interface to return more info for imp005 (this has to tell you the ethernet link type too, for example) - this will be imp.net.info() and available on imps from release 34. Info you get looks like this (subject to change before final release):

{
‘type’: string, # ‘wifi’
‘macaddress’: string, # cf. imp.getmacaddress()
‘bands’: string, # ‘2.4G’, ‘5G’ or ‘2.4G,5G’
‘country’: string, # cf. imp.getcountry()
‘powersave’: bool, # cf. imp.getpowersave()
‘channel’: integer, # cf. imp.getchannel()
‘rssi’: integer, # cf. imp.rssi(), but only present when wifi is up
’ssid’: string, # cf. imp.getssid()
‘bssid’: string, # cf. imp.getbssid(), but only present when wifi is up
’encryption’: string, # e.g. ‘WPA2-PSK (AES)’, but only present after first association
}

@Hugo,

has there been any progress on introducing support for an “atom store”?

No, but I’m tentatively trying to get one into release 36, though that depends somewhat on how much time there is left after the must-have things go in there (eg imp004m support).

We’re attempting to move to a 3 month OS release cycle, with release 34 soon to enter developer test - so release 36 should hopefully be a little over 3 months away.

Grateful to know. Your maths sounds slightly optimistic though. 34 -> 36 is 2 releases. 2 x 3 months = 6?

Ah, should have also made clear that even numbers are public releases. We are already on 35.1 internally :slight_smile:

[deleted]

The 4kB store, and connected SSID info, are both now implemented for release in impOS 36

Good news! Enables new product use cases.

Note that this applies to all imps (yes even 001) which I know will help some people’s applications that are already in the field :slight_smile:

Is there an eta for 36? I take it the release cycle is a bit longer than 3 months now :slight_smile:

First betas will be out by the end of this month, final release depends on what bugs are discovered… not quite 3 months since 34, but we’re doing better than we have done previously :slight_smile:

Cool thanks

Release 36 is going to beta this week - please look out for the announcements.