Skip to content

Multiple wifi #63

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

Closed
djh1997 opened this issue Mar 4, 2022 · 10 comments · Fixed by #65
Closed

Multiple wifi #63

djh1997 opened this issue Mar 4, 2022 · 10 comments · Fixed by #65

Comments

@djh1997
Copy link

djh1997 commented Mar 4, 2022

The secrets.py looks suspiciously like a wpa_supplicant.conf file but we can only put one wifi in there is there a way to put multiple as I would love my tag to work at home and office

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Mar 4, 2022

The libraries and all or most widely published user code currently are hard coded to expect a single entry in secrets with the network details. I am not aware of anything currently that would use any entries beyond the first.

The libraries could eventually be updated to attempt to use the next one in a list if the first one is not available and so on, but that change will need to be carried out in a few libraries before it's widely usable in an easy manner. I know some other folks have requested similar functionality but no one has had it prioritized strongly enough to do yet. We are definitely willing to review PRs for that if you are interested in working on it though.

That being said there are a few ways that you could try to minimize the effort involved in switching back and forth with the libraries as they exist today:

  1. make multiple secrets files like home_secrets.py and office_secrets.py each with their own respective network details. Then whenever you change locations you can copy/paste or rename one of the files to secrets.py so that it will be the one used.

  2. since secrets.py is a python file I think it can contain logic to make descisions. You could do something like this inside of it:

at_home = True
if at_home:
    secrets = {...} # home network details
else:
    secrets = {...} # office network details

Then you could change just the boolean whenever you need to switch networks.

@tekktrik
Copy link
Member

tekktrik commented Mar 4, 2022

It does also look like the base library adafruit_portalbase.network.NetworkBase allows for overriding using the contents of secrets.py using the secrets_data argument. Is it worth exposing that as an argument to both this libraries adafruit_magtag.network.Network and adafruit_magtag.magtag.MagTag?

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Mar 4, 2022

@tekktrik my understanding is that the classes in this library are extending the ones from the PortalBase library, so I think you can use that argument without needing to specifically add it into this library. Though adding it here explicitly would allow it to appear in the documentation I think.

@makermelissa
Copy link
Collaborator

@FoamyGuy is correct. PortalBase is the Base Class for all Portal style libraries.

@tekktrik
Copy link
Member

tekktrik commented Mar 4, 2022

I don't think any of that information actually gets passed to the base classes though. Here's my train of thought: It looks like the only things getting passed to Network in during MagTab.__init__() are these three arguments:

network = Network(
            status_neopixel=status_neopixel,
            extract_values=False,
            debug=debug,
        )

Network then goes on to initialize NetworkBase with the same values

super().__init__(
            WiFi(status_led=status_led),
            extract_values=extract_values,
            debug=debug,
        )

As is, MagTag.__init() (or the above) doesn't take other non-specified arguments either (via *args or **kwargs), so that would also need to be modified. Let me know if any of that is off!

@makermelissa
Copy link
Collaborator

I took a closer look at this. I had implemented this previously in the ESP32SPI library: https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/main/adafruit_esp32spi/adafruit_esp32spi_wifimanager.py#L133-L154 which just calls _get_next_ap to get the next access point.

However, the MagTag uses the built in ESP32-S2 WiFi stack, so it completely bypasses this. The best place to add this functionality would be in PortalBase in https://github.com/adafruit/Adafruit_CircuitPython_PortalBase/blob/main/adafruit_portalbase/wifi_esp32s2.py. This would also give the functionality to the FunHouse and ESP32S2TFT libraries which use this file as well. I would recommend a similar approach where username and password can be tuples or lists and then it iterates among those on each connection attempt and then loops back when it hits the end. If just a string are given for the username and password, it should just keep trying to use those.

Since this is more of a PortalBase feature, I'm going to move this issue there.

@makermelissa makermelissa transferred this issue from adafruit/Adafruit_CircuitPython_MagTag Mar 11, 2022
@makermelissa
Copy link
Collaborator

I think it only makes one attempt and if it doesn't see the WiFi SSID (perhaps it's down at that moment), it fails. So another thing would be to have it try multiple attempts on failure which is how the ESP32SPI lib works.

@tekktrik
Copy link
Member

It looks like it tries a few times on the provided ssid and password, unless I'm misunderstanding:

while not self._wifi.is_connected:
# secrets dictionary must contain 'ssid' and 'password' at a minimum
print("Connecting to AP", self._secrets["ssid"])
if (
self._secrets["ssid"] == "CHANGE ME"
or self._secrets["password"] == "CHANGE ME"
):
change_me = "\n" + "*" * 45
change_me += "\nPlease update the 'secrets.py' file on your\n"
change_me += "CIRCUITPY drive to include your local WiFi\n"
change_me += "access point SSID name in 'ssid' and SSID\n"
change_me += "password in 'password'. Then save to reload!\n"
change_me += "*" * 45
raise OSError(change_me)
self._wifi.neo_status(STATUS_NO_CONNECTION) # red = not connected
try:
self._wifi.connect(self._secrets["ssid"], self._secrets["password"])
self.requests = self._wifi.requests
except RuntimeError as error:
if max_attempts is not None and attempt >= max_attempts:
raise OSError(
"Maximum number of attempts reached when trying to connect to WiFi"
) from error
print("Could not connect to internet", error)
print("Retrying in 3 seconds...")
attempt += 1
time.sleep(3)
gc.collect()

@makermelissa
Copy link
Collaborator

makermelissa commented Mar 15, 2022

It looks like it tries a few times on the provided ssid and password, unless I'm misunderstanding:

Yeah, it looks like a ConnectionError is now returned, so #64 fixes that.

@djh1997
Copy link
Author

djh1997 commented Mar 16, 2022

thanks you everyone who's looking at this the idea is so i don't have to reprogram the tag so it looks like a change to allow a retry with next SSID on this part would be what would be an ideal implementation

It looks like it tries a few times on the provided ssid and password, unless I'm misunderstanding:

while not self._wifi.is_connected:
# secrets dictionary must contain 'ssid' and 'password' at a minimum
print("Connecting to AP", self._secrets["ssid"])
if (
self._secrets["ssid"] == "CHANGE ME"
or self._secrets["password"] == "CHANGE ME"
):
change_me = "\n" + "*" * 45
change_me += "\nPlease update the 'secrets.py' file on your\n"
change_me += "CIRCUITPY drive to include your local WiFi\n"
change_me += "access point SSID name in 'ssid' and SSID\n"
change_me += "password in 'password'. Then save to reload!\n"
change_me += "*" * 45
raise OSError(change_me)
self._wifi.neo_status(STATUS_NO_CONNECTION) # red = not connected
try:
self._wifi.connect(self._secrets["ssid"], self._secrets["password"])
self.requests = self._wifi.requests
except RuntimeError as error:
if max_attempts is not None and attempt >= max_attempts:
raise OSError(
"Maximum number of attempts reached when trying to connect to WiFi"
) from error
print("Could not connect to internet", error)
print("Retrying in 3 seconds...")
attempt += 1
time.sleep(3)
gc.collect()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants