Skip to content
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

esp.disconnect leaves the ESP32 in a bad state #133

Open
mikejc58 opened this issue Apr 9, 2021 · 2 comments
Open

esp.disconnect leaves the ESP32 in a bad state #133

mikejc58 opened this issue Apr 9, 2021 · 2 comments

Comments

@mikejc58
Copy link
Contributor

mikejc58 commented Apr 9, 2021

I am writing an application on a PyPortal that needs to talk to two access points. After connecting to the first and communicating via socket with a host there, I close the socket and do an esp.disconnect() to disconnect from the access point. This seems to work. The esp's status goes to WL_DISCONNECTED.
I then connect to the second access point with the esp's status going back to WL_CONNECTED. But, at that point the ESP seems to be in a bad state. Any function requiring communication with the AP fails, in one way or another. I wrote a simple test case that demonstrates the problem:

import board
from digitalio import DigitalInOut
import busio
import sys
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_socket

esp32_cs_pin = DigitalInOut(board.ESP_CS)
esp32_ready_pin = DigitalInOut(board.ESP_BUSY)
esp32_reset_pin = DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)

esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs_pin, esp32_ready_pin, esp32_reset_pin)

ssids = (('linkme', '***********'), ('corrigan', '**********'))
fwstr = str(esp.firmware_version, 'utf-8')

major, minor, sub = sys.implementation.version
print("Circuitpython {}.{}.{},  ESP32 firmware {}".format(major, minor, sub, fwstr))

test_ip = esp.unpretty_ip('192.168.43.148')
port = 65432

for ssid, password in ssids:
    print("Testing ssid = {}".format(ssid))

    # connect to an AP
    esp.connect_AP(ssid, password, timeout_s = 30)
    print("Create socket")

    # create a socket
    adafruit_esp32spi_socket.set_interface(esp)
    my_sock = adafruit_esp32spi_socket.socket()
    print("Connect socket")

    # connect to socket server on other system        
    my_sock.connect((test_ip, port))
    print("close socket")

    # close socket
    my_sock.close()
    print("disconnect from AP")

    # disconnect from AP
    esp.disconnect()    

The output is:

code.py output:
Circuitpython 6.1.0,  ESP32 firmware 1.7.3
Testing ssid = linkme
Create socket
Connect socket
close socket
disconnect from AP
Testing ssid = corrigan
Create socket
Connect socket
Traceback (most recent call last):
  File "code.py", line 35, in <module>
  File "adafruit_esp32spi/adafruit_esp32spi_socket.py", line 75, in connect
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 783, in socket_connect
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 685, in socket_open
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 345, in _send_command_get_response
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 296, in _wait_response_cmd
  File "/lib/adafruit_esp32spi/adafruit_esp32spi.py", line 199, in _wait_for_ready
RuntimeError: ESP32 not responding

Code done running.

Everything works for the first access point, and seems to work for the second until the attempt to connect the socket. It also fails in the same way if I re-connect to the first access point instead. Other functions also fail. For example, esp.get_host_by_name(host) fails with RuntimeError: Failed to request hostname.

A more elaborate test shows that after connecting to the second access point, the ESP32's internal state is inconsistent. Asking the ESP32 for the bssid and ssid that it is connected to show the second access point, but asking the ESP32 for its 'network data', gives back the ip address, and gateway of the first access point.

If I change the timeout in _wait_for_ready, I find that the socket.connect request actual finishes after 18 seconds (waiting for the response, the normal timeout is 10). But, when the socket.connect finishes, it is with a RuntimeError: Expected 01 but got 00, which is what you get when the connection fails.

If you do an esp.reset(), everything works again.

@mikejc58
Copy link
Contributor Author

mikejc58 commented Apr 9, 2021

The more elaborate test and its output:
elaborate.txt

@anecdata
Copy link
Member

anecdata commented Sep 15, 2021

ESP32SPI .disconnect simply calls disconnect in the NINA firmware, which uses the Arduino function WiFi.disconnect(). Similarly, ESP32SPI .connect calls into NINA, which does a WiFi.begin(ssid, pass). So I think we'd have to dig into the ESP32 implementation of the Arduino functions.

I suspect WiFiNINA would behave similarly, it would be interesting if it was different.

If you can incur the <1 second penalty of esp.reset(), that's probably the best workaround.

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

No branches or pull requests

2 participants