-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for esp32 network driver scanning for access points #1165
base: main
Are you sure you want to change the base?
Conversation
58cf1f8
to
cdadc33
Compare
I struggled here: I started out empty example and tried:
This crashes with: Then I read docs, about having to start the network, and tried:
which crashed with: delaying things and scanning after connection is done made it further to a crash:
It also seems that connecting to a network not available, disallows scanning with: Would be great seeing an example that could be used in CI eg:
I'll work on getting wokwi CI going so this can be covered by CI. |
I did not add an example yet, my plan was to write a demonstration of “roaming” for atomvm_examples. It is a little difficult to use until #1181 is merged, that will allow starting WiFi without immediately starting a connection. Scans will always fail when a connection is in progress, so your application will need to start a scan after obtaining an IP address, or before any connection is started (which is not possible until after #1181). |
I wish your second example had a stacktrace! You can see the scan result did come back with no networks found… this can happen with default scans (the dwell time is very short by default - and can easily miss networks, in my experience). I think it’s just a bad match in your test that is crashing there. |
ohh the embarrassment lol - it's the IO.inspect call that crashes, will look into it - used to throwing anything at IO.inspect.. Makes sense with the other stuff, suppose some kind of WifiManager GenServer will materialize, while this PR is on driver primitives level.. I'll test #1181 and help land that first.. |
My plan precisely! The PRs I have already submitted will provide all the necessary low level functionality, but I would like to create a higher level network_manager module that can simplify configuration and orchestration. |
As far as “dwell” time for the scan, I have found between 300-500ms will find all of the available networks, with the default (120ms) I do notice networks being frequently missed. |
cdadc33
to
b70a385
Compare
That does sound like a bug, from my limmited understanding of Elixir you should be able to give it just about anything, much like |
b70a385
to
aa3a56d
Compare
You did point me to a problem here, I started testing more boards and realized that even with maximum dwell time no network are being found. I cherry-picked these commits from a different local branch and must have missed something. |
480b056
to
50a78c7
Compare
When I split up the working branch I was testing new network features on I mistakenly submitted this PR first, but in order to use the scan function PR #1181 needs to be merged first, and this will need to be rebased. |
I did find a bug that would cause the results to be empty if only a single network was found, during most of my testing I had multiple networks, so this didn't get caught. @petermm, thanks for testing and helping me correct this! |
50a78c7
to
d0a4ea5
Compare
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
d0a4ea5
to
d72b955
Compare
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
d72b955
to
b3b0558
Compare
b3b0558
to
29c9c9f
Compare
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
29c9c9f
to
52d491f
Compare
2f5b0f4
to
204be04
Compare
could we improve DX for a fast moving dev who calls with no network started and gets:
Maybe catch that one and return error and log 'network must be started before calling wifi_scan' or similar.. otherwise great, once hidden network bug is solved! |
Great idea! I refrained from adding explanatory error logs when badarg is returned (i.e. warn that the pin number is out of range, etc...) it keep the driver from increasing in size too much, but this circumstance may be less obvious than a bad value for a pin or an invalid pull direction. |
204be04
to
36a0eca
Compare
I went one step further and just made that work. If the network has not been started it will be started in sta mode with the There was already a check for a valid mode once the port is open to the driver, so any other invalid mode will get an error log with an explanation. |
36a0eca
to
d74dab2
Compare
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
doc/src/network-programming-guide.md
Outdated
For example to do a passive scan, including hidden networks, using the longest allowed scan time and showing the maximum number of networks available use the following: | ||
|
||
```erlang | ||
{ok, Results} = network:wifi_scan([passive, {results, 20}, {dwell, 1500}, hidden]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
believe its show_hidden option? (not hidden)
works great! tested esp32(sim/real), and esp32c3 + esp32s2 The bssid stuff is most excellent, I'll try to get some wifi-geolocation going.. BUT, esp32 real world will consistently stack overflow if results option is higher than 14. :network.wifi_scan([:passive, {:results, 14}, {:dwell, 1500}, :show_hidden])
|> IO.inspect() works 100% of time, changing to results,15 (and above) stackoverflows 100% It seems to happen 100% even in a spot where it only finds around 7 networks.. |
|
This is very interesting, and I really appreciate the help testing... I don't know if I have enough outlets and power supplies to create enough networks to see what actually happens when it can find 20. I only pick up two, plus any extra APs hosted on MCUs for testing. We probably need to adjust the maximum number down for the esp32 classic. I do have esp32 with PSRAM to test with... it might work fine with the lower 4M added to the heap. At the very least the esp32 limit will need to be documented. |
s2 works with {results,20} - tested. Believe you just have to scan for 20 {results, 20}, you don't need to find 20 - if you get what I mean.. but seems there is some stack limit of 14 for esp32, we could also increase some stack most likely. |
doc/src/network-programming-guide.md
Outdated
|
||
Example return results: | ||
```erlang | ||
{ok,{13,[{"atomvm_test_ap",[{rssi,-25},{authmode,wpa_wpa2_psk},{channel,6}]}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs updating to new return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, I updated the edocs, but forgot to expand on that here in the Network Programming Guide. Thanks for catching that.
doc/src/network-programming-guide.md
Outdated
This function is currently only supported on the ESP32 platform. | ||
``` | ||
|
||
After the network has been configured for STA mode and started, as long as no connection has been initiated or associated, you may scan for available access points using [`network:wifi_scan/0`](./apidocs/erlang/eavmlib/network.md#wifi_scan1) or [`network:wifi_scan/1`](./apidocs/erlang/eavmlib/network.md#wifi_scan1). Scanning for access points will temporarily inhibit other traffic on the access point network if it is in use, but should not cause any active connections to be dropped. With no options, a default 'active' scan, with a per-channel dwell time of 120ms will be used and will return network details for up to 6 access points. The return value for the scan takes the form of a tuple consisting of `{ok, Results}`, where `Results = {FoundAPs [NetworkList]}`. `FoundAPs` may be a number larger than the length of the NetworkList if more access points were discoverd than the number of results requested. The entries in the `NetworkList` take the form of `{SSID, [AP_Properties]}`. `SSID` is the name of the network, and the `AP_Properties` is a proplist with the keys `rssi` for the dBm signal strength of the access point, `authmode` value is the authentication method used by the network, and the `channel` key for obtaining the primary channel for the network. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reword for new functionality, where a network isn't required to have been started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I felt like I was forgetting something.
0ba04f5
to
7998285
Compare
Corrects the type name db() to the more correct `dbm()`, and adds a brief edoc explanation for the value. Signed-off-by: Winford <[email protected]>
5643274
to
b071124
Compare
Reading the docs, I'm backtracking a bit on using wifi_scan with no network configured. It seems like it will implicitly bring you into an unwanted state of things, and it will work once, but not twice. I suggest just returning an error, so nobody ventures down a codepath they can't really recover from. I'll view this code as primitives and then somebody will make a atomvm_super_wifi lib, that can handle/abstract all of this. but just my 2 cents, obviously no strong opinions and PR is awesome! |
There are still use cases where this behavior would still be fine... like a device that only needs to discover which network to connect to when it first turned on, and is not expected to change networks unless it is powers off and moved to a new location... or even battery powered devices that choose the correct network when they wake up, and return to a sleeping state between connections. But I did feel I needed to make that more clear in the documentation that developers who choose to use this convenience are making a trade off. Most applications will still want to start the network first with a configuration with callback functions. |
Indeed. Eventually a network_manager module could offer some higher level abstractions. Especially once ethernet support is added, and possibly support for esp-hosted to support esp32 device wifi slaves for the ESP32-P4. |
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
For more fine grained connection management in applications the driver can now be started, without perfoming an inital connection, by the use of the key `managed` in the STA configuration. Adds network:sta_connect/0,1 to allow connecting to an access point after the driver has been started in STA or STA+AP mode. If the function is used without parameters a connection to the last configured access point will be started. Adds network:sta_disconnect/0 to disconnect a station from an access point. The station mode disconnected callback now maintains the default behavior of reconnecting to the last access point if the connection is lost, but if the user defines a custom callback the automatic re-connection will not happen, allowing for users to take advantage of scan results or some other means to determine when and which access point to associate with. The combination of the use of a disconnected callback and `managed` mode allow for the use of `network:wifi_scan/0,1` (PR atomvm#1165), since the wifi must not be connected to a station when perfoming a scan and the current implementation always starts a connection immediatly and always reconnects when disconnected. Signed-off-by: Winford <[email protected]>
Adds the ability for devices configured for sta or ap+sta to scan for available access points when not currently associated to an AP. With no arguments the default maximum results returned is 6. All default options can be configured in the `sta_config()` section of the configuration used to start the network driver, or set in the configuration parameter of `network:wifi_scan/1`. Signed-off-by: Winford <[email protected]>
Adds documentation for `network:wifi_scan/0,1` and updates details for `network:sta_rssi/0`, as well as better organizing the sub sections that these commands are documented in. Signed-off-by: Winford <[email protected]>
b071124
to
f25080c
Compare
Add
network:wifi_scan/0,1
to esp32 network driver, giving the ability for devices configured for "station mode" (or with "station + access point mode") to scan for available access points.note: these changes depend on PR #1181
These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later