Skip to content

Generic WiFi Design

Jenna Fox edited this page Oct 17, 2015 · 30 revisions

Here we are capturing the design of a generic WiFi interface that will be implemented by the likes of ESP8266. The name of the interface has not been finalized but in this document, we will assume it will be called wifi.

This page will be deleted and/or used for the basis of proper documentation when work has been completed. There is a forum thread discussing this work item. There is also an explicit work item tracking the detailed implementation and design (#589).

Before we go deep into design thoughts, it is always good to see what others have done. There is absolutely no reason that we don't just do exactly what has been done before. Here are some variants:

Also, please bear in mind that WiFi/Ethernet/GSM aren't the only ways to connect to the net. I'm pretty sure Thread/6LoWPAN will be getting extremely popular soon, and it'd be good to have an API for that which behaves in a similar way.


###setPower wifi.setPower(onOrOff, function(err) { ... })

Initialise WiFi, or turn it off. That could be handy?

  • onOrOff [Boolean] - Switch on or off the WiFi interface. Useful to switch off WiFi to reduce power consumption.

Comments

  • gw: setMode was suggested here - I think something like that makes more sense?
  • rakeshpai: I'd suggest not exposing this, maybe? I think espruino knows enough about whether the WiFi radio needs to be powered or not (using .createAP or .disconnect or similar methods), and should decide on the user's behalf. This would make it easier to use, and potentially result in power savings. Just thinking out loud.

###connect wifi.connect(ssid, key, [options], function(err) { ... });

Connect to the given access point. The options could be an object extra stuff like the security type.

The callback is called with err==null on success. Could maybe also return the IP?

####Comments

  • Kolban: When should the callback occur? Choices include when connected or when connected AND ready for use?
  • Sameh Hady: I guess callback should occur once connected and ready. ( My vote )
  • Kolban: My vote would be an object of properties as opposed to positional parameters.
  • Kolban: What should be in the options like data? For example static IP address, hostname etc etc?
  • Sameh Hady: Maybe an option to set auto connect true or false
  • rakeshpai: I think the callback should be called only when it's ready. If we want intermediate states, we could make .connect return an event emitter, to which we can add listeners. Eg: wifi.connect(...).on('...', function() { ... })
  • gw: My vote is for connected only too. Maybe wifi itself should emit DHCP/etc events. See rakeshpai's comments on setIP - maybe that could be removed and merged in here? Does that work nicely when we also consider connecting via Ethernet?

###disconnect Disconnect from an access point (assumes a previous connect()).

wifi.disconnect(function(err) { ... });


###getAPs wifi.getAPs(function(err, aps) { ... });

Call the callback with a list of discovered access points, of the form aps = [ { ssid, enc, signal_strength, mac_address } ].

The callback is called with err==null on success.

  • err - Error indication.
  • aps - Array of objects, one per found access point.

####Comments

  • tve: Should this be called scan as opposed to getAPs?
  • Sameh Hady: Vote for scan
  • rakeshpai: +1 for scan. We could consider .rssi instead of signal_strength, if it won't be confusing. Also, maybe .mac instead of .mac_address?
  • gw: ok, scan sounds good. The existing JS module uses ssid/enc/signal/mac and has done for a while. Is signal less confusing and shorter?

###getConnectedAP wifi.getConnectedAP(function(err, ap) { ... });

Call the callback with the name of the currently connected access point. The callback is called with err==null on success.

  • err - Error indication.
  • ap - Details of the currently connected access point.

####Comments

  • Kolban: What should be included in the response data?
  • gw: Unsure. Maybe it makes sense to merge this and getConnectedDevices?

###createAP wifi.createAP(ssid, key, channel, enc, function(err) { ... })

Create an access point with the given ssid, key, channel, and encoding. Encoding can be 0, undefined, "open", "wep", "wpa_psk", "wpa2_psk" or "wpa_wpa2_psk".

Example: wifi.createAP("ESP123","HelloWorld",5,"w­pa2_psk",print)

####Comments

  • Kolban: I had thought that a good name would have been becomeAP but I think I am now liking createAP better.
  • Kolban: My vote would be an object of properties as opposed to positional parameters.
  • gw: My preference is an object too - with sensible defaults (is there a channel that can be used legally in all regions? 5?)
  • rakeshpai: We'd need a corresponding method to stop the AP as well. Symmetric sounding names might be a good idea, ala startAP and stopAP. Also, +1 for object. There are other properties we can set when creating an AP (example), and having them as positional arguments would make it difficult to use.

###stopAP wifi.stopAP(function() { ... })

Stops an access point.

####Comments

  • gw : Does it make sense to just have disconnect - which stops the AP and/or disconnects from whatever it was connected to? Seems strange having to have 2 functions that do almost the same thing but in different circumstances.
  • bluebie: the ESP8266 can be connected to an AP while also producing it's own AP, so it does make sense to be able to disconnect the client function and the server function individually.

###getConnectedDevices wifi.getConnectedDevices(function(err, devices) { ... });

If if AP mode (with wifi.createAP), call the callback with the second argument as an array of { ip, mac } objects - one for each connected device.

####Comments

  • Kolban: I am not a fan of the name of the function. I would suggest something like getConnectedStations as it aren't devices which connect to access points but rather stations.

###getIP wifi.getIP(function(err, ip) { ... });

Call the callback with the current address details: {ip:string, mac:string, ...?}

The callback is called with err==null on success.

####Comments

  • Sameh Hady: I prefer to make this function generic, something like wifi.info(function(err, wifi) { ... }) that returns an object ( wifi.ip, wifi.mac, etc )
  • gw: The suggestion is that this is generic (in all but name), returning all that info. Choice of name is because that's what is currently implemented, but it could be changed. If it were changed I think there must be something more informative than info though. Probably needs to be getX to mirror a setX too.
  • rakeshpai: Node uses [os.networkInterfaces](https://nodejs.org/api/os.html#os_os_networkinterfaces), which could be interesting. We'd need to use a plural, since the hardware can be on multiple networks simultaneously, eg. acting as both a station and an AP. Also, would this need to be an asynchronous call? (It might be best to keep it async for compatibility though.)
  • gw: yep, it'd need to be async to also work on other devices (like ESP8266 via AT commands). Interesting about multiple interfaces, but IMO in terms of name, networkInterfaces isn't really very obvious, and what would the setter version be? I'd say 95% of the time people will just use this to get the IP, so it'd be nice to make it easy to use for that case.

###setIP wifi.setIP(data, function(err) { ... });

Call the function with address details - items left out are not changed: {ip:string, mac:string, ...?}

Current behaviour on CC3000/WIZnet is to do DHCP if called without arguments.

The callback is called with err==null on success.

####Comments

  • rakeshpai: I'd vote against having this method, and rolling the configuration into the arguments accepted by .createAP or .connect methods instead.
  • gw: interesting. It'd still be nice to be able to force DHCP, but I guess a connect to the same AP without a disconnect first could do that. We also need to think about Ethernet/GSM, but I guess connect could work in those cases too.

###setDNS wifi.setDNS(dnsServers)

Sets the DNS servers that should be used.

Example: `wifi.setDNS(["8.8.8.8", "8.8.4.4"]);

####Comments

  • rakeshpai: Not entirely sure about where this method should exist. Is wifi even the right place? Also, should this method exist at all, or should this just be part of the config required to start a connection?
  • gw: I'd vote for sticking it as an option in connect - or if we're keeping setIP to put it in there - after all, chances are if you're setting DNS you want it set alongside IP/Gateway/etc.

###rssi wifi.rssi() or wifi.rssi('access point')

Gets the signal strength of the router when connected to it, or of an access point if specified.

####Comments

  • gw: I'd be in favour of scrapping this? I wonder how often it'd be used, and .scan should do this for you (although it would obviously return other access points too). If getIP is being renamed to something more generic like networkInterfaces, the data could go in there too.

#Design Questions

How to save state for a WiFi instance?

We are now looking towards low-level design. The goal here is to make a new library called wifi that can then be created with require("wifi"). However, is this the right thing? Should wifi not be a class that we can create with new WiFi() so that we can save state within it?

Here is my thinking. For many of the methods, we will be changing the state of our WiFi instance. For example, when we call connect(myFunc) ... we need to save the reference to the myFunc function so that when we do connect, the function can be called. The way we had been saving this was as C language globals that hold JsVar references. However I'm thinking that is wrong. Given that we now have a variable (I think) that is an instance of a WiFi ... can't we hang these callbacks off this variable as hidden properties?

This is where we need gw to assist.

Clone this wiki locally