helpers for sync_time
ruff was getting upset about too many branches
This commit is contained in:
parent
2e19356d9a
commit
d2ae05eaed
1 changed files with 77 additions and 64 deletions
|
|
@ -224,8 +224,7 @@ class Network(NetworkBase):
|
||||||
NTP_SERVER – NTP host (default: "pool.ntp.org")
|
NTP_SERVER – NTP host (default: "pool.ntp.org")
|
||||||
NTP_TZ – timezone offset in hours (float, default: 0)
|
NTP_TZ – timezone offset in hours (float, default: 0)
|
||||||
NTP_DST – extra offset for daylight saving (0=no, 1=yes; default: 0)
|
NTP_DST – extra offset for daylight saving (0=no, 1=yes; default: 0)
|
||||||
NTP_INTERVAL – re-sync interval in seconds (default: 3600, not used internally,
|
NTP_INTERVAL – re-sync interval in seconds (default: 3600, not used internally)
|
||||||
but available for user loop scheduling)
|
|
||||||
|
|
||||||
NTP_TIMEOUT – socket timeout per attempt (seconds, default: 5.0)
|
NTP_TIMEOUT – socket timeout per attempt (seconds, default: 5.0)
|
||||||
NTP_CACHE_SECONDS – cache results, 0 = always fetch fresh (default: 0)
|
NTP_CACHE_SECONDS – cache results, 0 = always fetch fresh (default: 0)
|
||||||
|
|
@ -249,86 +248,100 @@ class Network(NetworkBase):
|
||||||
Returns:
|
Returns:
|
||||||
time.struct_time
|
time.struct_time
|
||||||
"""
|
"""
|
||||||
# Bring up Wi-Fi using the existing flow.
|
# Ensure Wi-Fi up
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
# Build a socket pool from the existing ESP interface.
|
# Socket pool
|
||||||
pool = acm.get_radio_socketpool(self._wifi.esp)
|
pool = acm.get_radio_socketpool(self._wifi.esp)
|
||||||
|
|
||||||
# Settings with environment fallbacks.
|
# Settings & overrides
|
||||||
server = server or os.getenv("NTP_SERVER") or "pool.ntp.org"
|
server = server or os.getenv("NTP_SERVER") or "pool.ntp.org"
|
||||||
|
tz = tz_offset if tz_offset is not None else _combined_tz_offset(0.0)
|
||||||
if tz_offset is None:
|
|
||||||
tz_env = os.getenv("NTP_TZ")
|
|
||||||
try:
|
|
||||||
tz_offset = float(tz_env) if tz_env not in {None, ""} else 0.0
|
|
||||||
except Exception:
|
|
||||||
tz_offset = 0.0
|
|
||||||
|
|
||||||
# Simple DST additive offset (no IANA time zone logic).
|
|
||||||
try:
|
|
||||||
dst = float(os.getenv("NTP_DST") or 0)
|
|
||||||
except Exception:
|
|
||||||
dst = 0.0
|
|
||||||
tz_offset += dst
|
|
||||||
|
|
||||||
# Optional tuning (env can override passed defaults).
|
|
||||||
t = tuning or {}
|
t = tuning or {}
|
||||||
|
|
||||||
def _f(name, default):
|
timeout = float(t.get("timeout", _get_float_env("NTP_TIMEOUT", 5.0)))
|
||||||
v = os.getenv(name)
|
cache_seconds = int(t.get("cache_seconds", _get_int_env("NTP_CACHE_SECONDS", 0)))
|
||||||
try:
|
require_year = int(t.get("require_year", _get_int_env("NTP_REQUIRE_YEAR", 2022)))
|
||||||
return float(v) if v not in {None, ""} else float(default)
|
ntp_retries = int(t.get("retries", _get_int_env("NTP_RETRIES", 8)))
|
||||||
except Exception:
|
ntp_delay_s = float(t.get("retry_delay", _get_float_env("NTP_DELAY_S", 1.0)))
|
||||||
return float(default)
|
|
||||||
|
|
||||||
def _i(name, default):
|
# NTP client
|
||||||
v = os.getenv(name)
|
|
||||||
try:
|
|
||||||
return int(v) if v not in {None, ""} else int(default)
|
|
||||||
except Exception:
|
|
||||||
return int(default)
|
|
||||||
|
|
||||||
timeout = float(t.get("timeout", _f("NTP_TIMEOUT", 5.0)))
|
|
||||||
cache_seconds = int(t.get("cache_seconds", _i("NTP_CACHE_SECONDS", 0)))
|
|
||||||
require_year = int(t.get("require_year", _i("NTP_REQUIRE_YEAR", 2022)))
|
|
||||||
|
|
||||||
# Query NTP and set the system RTC.
|
|
||||||
ntp = adafruit_ntp.NTP(
|
ntp = adafruit_ntp.NTP(
|
||||||
pool,
|
pool,
|
||||||
server=server,
|
server=server,
|
||||||
tz_offset=tz_offset,
|
tz_offset=tz,
|
||||||
socket_timeout=timeout,
|
socket_timeout=timeout,
|
||||||
cache_seconds=cache_seconds,
|
cache_seconds=cache_seconds,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Multiple reply attempts on transient timeouts
|
# Attempt fetch (retries on timeout)
|
||||||
ntp_retries = int(t.get("retries", _i("NTP_RETRIES", 8)))
|
now = _ntp_get_datetime(
|
||||||
ntp_delay_s = float(t.get("retry_delay", _f("NTP_DELAY_S", 1.0)))
|
ntp,
|
||||||
|
connect_cb=self.connect,
|
||||||
last_exc = None
|
retries=ntp_retries,
|
||||||
for attempt in range(ntp_retries):
|
delay_s=ntp_delay_s,
|
||||||
try:
|
debug=getattr(self, "_debug", False),
|
||||||
now = ntp.datetime # struct_time
|
)
|
||||||
break # success
|
|
||||||
except OSError as e:
|
|
||||||
last_exc = e
|
|
||||||
# Only retry on timeout-like errors
|
|
||||||
if getattr(e, "errno", None) == 116 or "ETIMEDOUT" in str(e):
|
|
||||||
# Reassert Wi-Fi via existing policy, then wait a bit
|
|
||||||
self.connect()
|
|
||||||
if self._debug:
|
|
||||||
print("NTP timeout, retry", attempt + 1, "of", ntp_retries)
|
|
||||||
time.sleep(ntp_delay_s)
|
|
||||||
continue
|
|
||||||
# Non-timeout: don't spin
|
|
||||||
break
|
|
||||||
|
|
||||||
if last_exc and "now" not in locals():
|
|
||||||
raise last_exc
|
|
||||||
|
|
||||||
|
# Sanity check & commit
|
||||||
if now.tm_year < require_year:
|
if now.tm_year < require_year:
|
||||||
raise RuntimeError("NTP returned an unexpected year; not setting RTC")
|
raise RuntimeError("NTP returned an unexpected year; not setting RTC")
|
||||||
|
|
||||||
rtc.RTC().datetime = now
|
rtc.RTC().datetime = now
|
||||||
return now
|
return now
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Internal helpers to keep sync_time() small and Ruff-friendly ----
|
||||||
|
|
||||||
|
|
||||||
|
def _get_float_env(name, default):
|
||||||
|
v = os.getenv(name)
|
||||||
|
try:
|
||||||
|
return float(v) if v not in {None, ""} else float(default)
|
||||||
|
except Exception:
|
||||||
|
return float(default)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_int_env(name, default):
|
||||||
|
v = os.getenv(name)
|
||||||
|
if v in {None, ""}:
|
||||||
|
return int(default)
|
||||||
|
try:
|
||||||
|
return int(v)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
return int(float(v)) # tolerate "5.0"
|
||||||
|
except Exception:
|
||||||
|
return int(default)
|
||||||
|
|
||||||
|
|
||||||
|
def _combined_tz_offset(base_default):
|
||||||
|
"""Return tz offset hours including DST via env (NTP_TZ + NTP_DST)."""
|
||||||
|
tz = _get_float_env("NTP_TZ", base_default)
|
||||||
|
dst = _get_float_env("NTP_DST", 0)
|
||||||
|
return tz + dst
|
||||||
|
|
||||||
|
|
||||||
|
def _ntp_get_datetime(ntp, connect_cb, retries, delay_s, debug=False):
|
||||||
|
"""Fetch ntp.datetime with limited retries on timeout; re-connect between tries."""
|
||||||
|
last_exc = None
|
||||||
|
for i in range(retries):
|
||||||
|
last_exc = None
|
||||||
|
try:
|
||||||
|
return ntp.datetime # struct_time
|
||||||
|
except OSError as e:
|
||||||
|
last_exc = e
|
||||||
|
is_timeout = (getattr(e, "errno", None) == 116) or ("ETIMEDOUT" in str(e))
|
||||||
|
if not is_timeout:
|
||||||
|
break
|
||||||
|
if debug:
|
||||||
|
print(f"NTP timeout, attempt {i + 1}/{retries}")
|
||||||
|
connect_cb() # re-assert Wi-Fi using existing policy
|
||||||
|
time.sleep(delay_s)
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
last_exc = e
|
||||||
|
break
|
||||||
|
if last_exc:
|
||||||
|
raise last_exc
|
||||||
|
raise RuntimeError("NTP sync failed")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue