circuitpython: ESP32S2 time.sleep(60) fails but time.sleep(15) works

May be related to https://github.com/adafruit/Adafruit_CircuitPython_Requests/issues/63

On a SAOLA WROVER If I run the code below with time.sleep(15) it executes normally but with time.sleep(60) it executes normally for the first pass throws and error ENOTCONN on the second pass but recovers then fails on the thirds and subsequent passes

Am I doing something wrong? has time.sleep() changed?


Adafruit CircuitPython 6.2.0-beta.0-3-g97f5d218a on 2021-01-24; Saola 1 w/Wrover with ESP32S2
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

code.py output:
<Network> Needell Airport -57 6
<Network> Needell Airport -41 1
<Network> central2.4 -76 7
<Network> 31A -77 7
<Network> PC -89 10
None
ip 10.0.0.111
Counter: 0
Sending to Adafruit IO...
Data sent!
Counter: 1
Sending to Adafruit IO...
Error sendind data - try again  [Errno 128] ENOTCONN
Counter: 1
Sending to Adafruit IO...
Data sent!
Counter: 2
Sending to Adafruit IO...
Error sendind data - try again  [Errno 128] ENOTCONN
Counter: 2
Sending to Adafruit IO...
Error sendind data - try again  Repeated socket failures
Counter: 2
Sending to Adafruit IO...
Error sendind data - try again  Repeated socket failures
Counter: 2
Sending to Adafruit IO...

here is the code

import ipaddress
import wifi
import socketpool
import time
import adafruit_requests
import ssl
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
import board
import busio
import digitalio

try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

for network in wifi.radio.start_scanning_networks():
    print(network, network.ssid, network.rssi, network.channel)

wifi.radio.stop_scanning_networks()

print(wifi.radio.connect(secrets["ssid"], secrets["password"]))

print("ip", wifi.radio.ipv4_address)

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())


aio_username = secrets["aio_username"]
aio_key = secrets["aio_key"]

# Initialize an Adafruit IO HTTP API object
io = IO_HTTP(aio_username, aio_key, requests)

try:
    feed = io.get_feed("test")
except AdafruitIO_RequestError:
    # If no feed exists, create one
    feed = io.create_new_feed("test")

counter = 0
while True:
    data = "%d" % (counter)
    try:
        print("Counter: {0}".format(counter))
        print("Sending to Adafruit IO...")
        io.send_data(feed["key"], counter)
        print("Data sent!")
        counter += 1
    except Exception as e:
        print("Error sendind data - try again ", e)
        continue
    time.sleep(60)

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (5 by maintainers)

Most upvoted comments

This turned out to be a 4(!) part issue:

  • The very first problem was that Failed SSL handshake was being mis-reported as [Errno 128] ENOTCONN by send(). That was my bad, it just needed some extra code to check the MbedTLS errors properly.
  • The first “real” problem, which @jerryneedell was encountering, was that only _SendFailed exceptions were being caught when Requests made a send_request. So when an SSL connection timed out, which was the case for the 60s delay, the resulting Failed SSL handshake error was being completely ignored, and the program would go on to try and do a recv_into on an invalid pipe and throw another Failed SSL handshake (accidentally shown as ENOTCONN). Issue here: adafruit/Adafruit_CircuitPython_Requests#67
  • This exception, when caught in code.py, would cause a socket leak, causing the sockets to run out. I’ve also discovered that all TLS sockets actually use two sockets, one you know about and a secret one under the hood, so an ESP32-S2 has a max of just two TLS sockets before it runs out. This isn’t an issue, just annoying.
  • Solving these problems (fixing the error message, and making the except: catch all errors) then results in adafruit/Adafruit_Circuitpython_Requests#66, seen as a mysterious Error sending data - try again <SSLSocket> message. Long story short this is because the hash was changing when the socket closed. More details in issue.

I still don’t know if any of this is related to adafruit/Adafruit_Circuitpython_Requests#63. @anecdata you could try out some of these changes and see if they help with your problem.

For Circuitpython, the changes that need to happen are the fix to send() error messages, and changing the Socket get_hash methods to return their own id() values rather than the socket number (pending further conversation in #4101). I’ll try and fold them into #4049 since trying to put them in separately would just cause messy merge issues.

I’m closing this issue now as @jerryneedell’s remaining issue is in the Requests library and is continued in this issue: https://github.com/adafruit/Adafruit_CircuitPython_Requests/issues/67

@jerryneedell you’d need to go into Requests and search for except _SendFailed and replace it with except (_SendFailed, OSError):