Skip to content

Commit d2ae05e

Browse files
committed
helpers for sync_time
ruff was getting upset about too many branches
1 parent 2e19356 commit d2ae05e

File tree

1 file changed

+77
-64
lines changed

1 file changed

+77
-64
lines changed

adafruit_fruitjam/network.py

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,7 @@ def sync_time(self, server=None, tz_offset=None, tuning=None):
224224
NTP_SERVER – NTP host (default: "pool.ntp.org")
225225
NTP_TZ – timezone offset in hours (float, default: 0)
226226
NTP_DST – extra offset for daylight saving (0=no, 1=yes; default: 0)
227-
NTP_INTERVAL – re-sync interval in seconds (default: 3600, not used internally,
228-
but available for user loop scheduling)
227+
NTP_INTERVAL – re-sync interval in seconds (default: 3600, not used internally)
229228
230229
NTP_TIMEOUT – socket timeout per attempt (seconds, default: 5.0)
231230
NTP_CACHE_SECONDS – cache results, 0 = always fetch fresh (default: 0)
@@ -249,86 +248,100 @@ def sync_time(self, server=None, tz_offset=None, tuning=None):
249248
Returns:
250249
time.struct_time
251250
"""
252-
# Bring up Wi-Fi using the existing flow.
251+
# Ensure Wi-Fi up
253252
self.connect()
254253

255-
# Build a socket pool from the existing ESP interface.
254+
# Socket pool
256255
pool = acm.get_radio_socketpool(self._wifi.esp)
257256

258-
# Settings with environment fallbacks.
257+
# Settings & overrides
259258
server = server or os.getenv("NTP_SERVER") or "pool.ntp.org"
260-
261-
if tz_offset is None:
262-
tz_env = os.getenv("NTP_TZ")
263-
try:
264-
tz_offset = float(tz_env) if tz_env not in {None, ""} else 0.0
265-
except Exception:
266-
tz_offset = 0.0
267-
268-
# Simple DST additive offset (no IANA time zone logic).
269-
try:
270-
dst = float(os.getenv("NTP_DST") or 0)
271-
except Exception:
272-
dst = 0.0
273-
tz_offset += dst
274-
275-
# Optional tuning (env can override passed defaults).
259+
tz = tz_offset if tz_offset is not None else _combined_tz_offset(0.0)
276260
t = tuning or {}
277261

278-
def _f(name, default):
279-
v = os.getenv(name)
280-
try:
281-
return float(v) if v not in {None, ""} else float(default)
282-
except Exception:
283-
return float(default)
284-
285-
def _i(name, default):
286-
v = os.getenv(name)
287-
try:
288-
return int(v) if v not in {None, ""} else int(default)
289-
except Exception:
290-
return int(default)
291-
292-
timeout = float(t.get("timeout", _f("NTP_TIMEOUT", 5.0)))
293-
cache_seconds = int(t.get("cache_seconds", _i("NTP_CACHE_SECONDS", 0)))
294-
require_year = int(t.get("require_year", _i("NTP_REQUIRE_YEAR", 2022)))
262+
timeout = float(t.get("timeout", _get_float_env("NTP_TIMEOUT", 5.0)))
263+
cache_seconds = int(t.get("cache_seconds", _get_int_env("NTP_CACHE_SECONDS", 0)))
264+
require_year = int(t.get("require_year", _get_int_env("NTP_REQUIRE_YEAR", 2022)))
265+
ntp_retries = int(t.get("retries", _get_int_env("NTP_RETRIES", 8)))
266+
ntp_delay_s = float(t.get("retry_delay", _get_float_env("NTP_DELAY_S", 1.0)))
295267

296-
# Query NTP and set the system RTC.
268+
# NTP client
297269
ntp = adafruit_ntp.NTP(
298270
pool,
299271
server=server,
300-
tz_offset=tz_offset,
272+
tz_offset=tz,
301273
socket_timeout=timeout,
302274
cache_seconds=cache_seconds,
303275
)
304276

305-
# Multiple reply attempts on transient timeouts
306-
ntp_retries = int(t.get("retries", _i("NTP_RETRIES", 8)))
307-
ntp_delay_s = float(t.get("retry_delay", _f("NTP_DELAY_S", 1.0)))
308-
309-
last_exc = None
310-
for attempt in range(ntp_retries):
311-
try:
312-
now = ntp.datetime # struct_time
313-
break # success
314-
except OSError as e:
315-
last_exc = e
316-
# Only retry on timeout-like errors
317-
if getattr(e, "errno", None) == 116 or "ETIMEDOUT" in str(e):
318-
# Reassert Wi-Fi via existing policy, then wait a bit
319-
self.connect()
320-
if self._debug:
321-
print("NTP timeout, retry", attempt + 1, "of", ntp_retries)
322-
time.sleep(ntp_delay_s)
323-
continue
324-
# Non-timeout: don't spin
325-
break
326-
327-
if last_exc and "now" not in locals():
328-
raise last_exc
277+
# Attempt fetch (retries on timeout)
278+
now = _ntp_get_datetime(
279+
ntp,
280+
connect_cb=self.connect,
281+
retries=ntp_retries,
282+
delay_s=ntp_delay_s,
283+
debug=getattr(self, "_debug", False),
284+
)
329285

286+
# Sanity check & commit
330287
if now.tm_year < require_year:
331288
raise RuntimeError("NTP returned an unexpected year; not setting RTC")
332289

333290
rtc.RTC().datetime = now
334291
return now
292+
293+
294+
# ---- Internal helpers to keep sync_time() small and Ruff-friendly ----
295+
296+
297+
def _get_float_env(name, default):
298+
v = os.getenv(name)
299+
try:
300+
return float(v) if v not in {None, ""} else float(default)
301+
except Exception:
302+
return float(default)
303+
304+
305+
def _get_int_env(name, default):
306+
v = os.getenv(name)
307+
if v in {None, ""}:
308+
return int(default)
309+
try:
310+
return int(v)
311+
except Exception:
312+
try:
313+
return int(float(v)) # tolerate "5.0"
314+
except Exception:
315+
return int(default)
316+
317+
318+
def _combined_tz_offset(base_default):
319+
"""Return tz offset hours including DST via env (NTP_TZ + NTP_DST)."""
320+
tz = _get_float_env("NTP_TZ", base_default)
321+
dst = _get_float_env("NTP_DST", 0)
322+
return tz + dst
323+
324+
325+
def _ntp_get_datetime(ntp, connect_cb, retries, delay_s, debug=False):
326+
"""Fetch ntp.datetime with limited retries on timeout; re-connect between tries."""
327+
last_exc = None
328+
for i in range(retries):
329+
last_exc = None
330+
try:
331+
return ntp.datetime # struct_time
332+
except OSError as e:
333+
last_exc = e
334+
is_timeout = (getattr(e, "errno", None) == 116) or ("ETIMEDOUT" in str(e))
335+
if not is_timeout:
336+
break
337+
if debug:
338+
print(f"NTP timeout, attempt {i + 1}/{retries}")
339+
connect_cb() # re-assert Wi-Fi using existing policy
340+
time.sleep(delay_s)
341+
continue
342+
except Exception as e:
343+
last_exc = e
344+
break
345+
if last_exc:
346+
raise last_exc
347+
raise RuntimeError("NTP sync failed")

0 commit comments

Comments
 (0)