Skip to content

Consolidate retry-logic #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

Merged
merged 8 commits into from
Oct 3, 2022
85 changes: 49 additions & 36 deletions adafruit_espatcontrol/adafruit_espatcontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,34 +135,39 @@ def begin(self) -> None:
except OKError:
pass # retry

def connect(self, secrets: Dict[str, Union[str, int]]) -> None:
def connect(
self, secrets: Dict[str, Union[str, int]], timeout: int = 15, retries: int = 3
) -> None:
"""Repeatedly try to connect to an access point with the details in
the passed in 'secrets' dictionary. Be sure 'ssid' and 'password' are
defined in the secrets dict! If 'timezone' is set, we'll also configure
SNTP"""
# Connect to WiFi if not already
retries = 3
while True:
try:
if not self._initialized or retries == 0:
self.begin()
retries = 3
AP = self.remote_AP # pylint: disable=invalid-name
print("Connected to", AP[0])
if AP[0] != secrets["ssid"]:
self.join_AP(secrets["ssid"], secrets["password"])
if "timezone" in secrets:
tzone = secrets["timezone"]
ntp = None
if "ntp_server" in secrets:
ntp = secrets["ntp_server"]
self.sntp_config(True, tzone, ntp)
print("My IP Address:", self.local_ip)
return # yay!
except (RuntimeError, OKError) as exp:
print("Failed to connect, retrying\n", exp)
retries -= 1
continue
try:
if not self._initialized:
self.begin()
AP = self.remote_AP # pylint: disable=invalid-name
if AP[0] != secrets["ssid"]:
self.join_AP(
secrets["ssid"],
secrets["password"],
timeout=timeout,
retries=retries,
)
print("Connected to", secrets["ssid"])
if "timezone" in secrets:
tzone = secrets["timezone"]
ntp = None
if "ntp_server" in secrets:
ntp = secrets["ntp_server"]
self.sntp_config(True, tzone, ntp)
print("My IP Address:", self.local_ip)
else:
print("Already connected to", AP[0])
return # yay!
except (RuntimeError, OKError) as exp:
print("Failed to connect\n", exp)
raise

# *************************** SOCKET SETUP ****************************

Expand Down Expand Up @@ -462,7 +467,9 @@ def remote_AP(self) -> List[Union[int, str, None]]: # pylint: disable=invalid-n
return reply
return [None] * 4

def join_AP(self, ssid: str, password: str) -> None: # pylint: disable=invalid-name
def join_AP( # pylint: disable=invalid-name
self, ssid: str, password: str, timeout: int = 15, retries: int = 3
) -> None:
"""Try to join an access point by name and password, will return
immediately if we're already connected and won't try to reconnect"""
# First make sure we're in 'station' mode so we can connect to AP's
Expand All @@ -472,17 +479,18 @@ def join_AP(self, ssid: str, password: str) -> None: # pylint: disable=invalid-
router = self.remote_AP
if router and router[0] == ssid:
return # we're already connected!
for _ in range(3):
reply = self.at_response(
'AT+CWJAP="' + ssid + '","' + password + '"', timeout=15, retries=3
)
if b"WIFI CONNECTED" not in reply:
print("no CONNECTED")
raise RuntimeError("Couldn't connect to WiFi")
if b"WIFI GOT IP" not in reply:
print("no IP")
raise RuntimeError("Didn't get IP address")
return
reply = self.at_response(
'AT+CWJAP="' + ssid + '","' + password + '"',
timeout=timeout,
retries=retries,
)
if b"WIFI CONNECTED" not in reply:
print("no CONNECTED")
raise RuntimeError("Couldn't connect to WiFi")
if b"WIFI GOT IP" not in reply:
print("no IP")
raise RuntimeError("Didn't get IP address")
return

def scan_APs( # pylint: disable=invalid-name
self, retries: int = 3
Expand Down Expand Up @@ -578,7 +586,12 @@ def at_response(self, at_cmd: str, timeout: int = 5, retries: int = 3) -> bytes:
# special case, ping also does not return an OK
if "AT+PING" in at_cmd and b"ERROR\r\n" in response:
return response
if response[-4:] != b"OK\r\n":
# special case, does return OK but in fact it is busy
if (
"AT+CIFSR" in at_cmd
and b"busy" in response
or response[-4:] != b"OK\r\n"
):
time.sleep(1)
continue
return response[:-4]
Expand Down
29 changes: 11 additions & 18 deletions adafruit_espatcontrol/adafruit_espatcontrol_wifimanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(
:param dict secrets: The WiFi and Adafruit IO secrets dict (See examples)
:param status_pixel: (Optional) The pixel device - A NeoPixel or DotStar (default=None)
:type status_pixel: NeoPixel or DotStar
:param int attempts: (Optional) Failed attempts before resetting the ESP32 (default=2)
:param int attempts: (Optional) Unused, only for compatibility for old code
"""
# Read the settings
self._esp = esp
Expand All @@ -60,26 +60,19 @@ def reset(self) -> None:
print("Resetting ESP")
self._esp.hard_reset()

def connect(self) -> None:
def connect(self, timeout: int = 15, retries: int = 3) -> None:
"""
Attempt to connect to WiFi using the current settings
"""
failure_count = 0
while not self._esp.is_connected:
try:
if self.debug:
print("Connecting to AP...")
self.pixel_status((100, 0, 0))
self._esp.connect(self.secrets)
failure_count = 0
self.pixel_status((0, 100, 0))
except (ValueError, RuntimeError) as error:
print("Failed to connect, retrying\n", error)
failure_count += 1
if failure_count >= self.attempts:
failure_count = 0
self.reset()
continue
try:
if self.debug:
print("Connecting to AP...")
self.pixel_status((100, 0, 0))
self._esp.connect(self.secrets, timeout=timeout, retries=retries)
self.pixel_status((0, 100, 0))
except (ValueError, RuntimeError) as error:
print("Failed to connect\n", error)
raise

def get(self, url: str, **kw: Any) -> requests.Response:
"""
Expand Down