|
26 | 26 |
|
27 | 27 | import gc |
28 | 28 | import os |
| 29 | +import time |
29 | 30 |
|
30 | 31 | import adafruit_connection_manager as acm |
31 | 32 | import adafruit_ntp |
@@ -219,20 +220,31 @@ def sync_time(self, server=None, tz_offset=None, tuning=None): |
219 | 220 | Set the system RTC via NTP using this Network's Wi-Fi connection. |
220 | 221 |
|
221 | 222 | Reads optional settings from settings.toml: |
222 | | - NTP_SERVER (default "pool.ntp.org") |
223 | | - NTP_TZ (float hours from UTC, default 0) |
224 | | - NTP_DST (additional offset, usually 0 or 1) |
225 | | - NTP_TIMEOUT (seconds, default 5.0) |
226 | | - NTP_CACHE_SECONDS (default 0 = always fetch fresh) |
227 | | - NTP_REQUIRE_YEAR (minimum acceptable year, default 2022) |
| 223 | +
|
| 224 | + NTP_SERVER – NTP host (default: "pool.ntp.org") |
| 225 | + NTP_TZ – timezone offset in hours (float, default: 0) |
| 226 | + 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) |
| 229 | +
|
| 230 | + NTP_TIMEOUT – socket timeout per attempt (seconds, default: 5.0) |
| 231 | + NTP_CACHE_SECONDS – cache results, 0 = always fetch fresh (default: 0) |
| 232 | + NTP_REQUIRE_YEAR – minimum acceptable year (default: 2022) |
| 233 | +
|
| 234 | + NTP_RETRIES – number of NTP fetch attempts on timeout (default: 8) |
| 235 | + NTP_DELAY_S – delay between retries in seconds (default: 1.0) |
228 | 236 |
|
229 | 237 | Keyword args: |
230 | 238 | server (str) – override NTP_SERVER |
231 | 239 | tz_offset (float) – override NTP_TZ (+ NTP_DST still applied) |
232 | | - tuning (dict) – override other knobs: |
233 | | - {"timeout": 5.0, |
234 | | - "cache_seconds": 0, |
235 | | - "require_year": 2022} |
| 240 | + tuning (dict) – override tuning knobs, e.g.: |
| 241 | + { |
| 242 | + "timeout": 5.0, |
| 243 | + "cache_seconds": 0, |
| 244 | + "require_year": 2022, |
| 245 | + "retries": 8, |
| 246 | + "retry_delay": 1.0, |
| 247 | + } |
236 | 248 |
|
237 | 249 | Returns: |
238 | 250 | time.struct_time |
@@ -290,25 +302,30 @@ def _i(name, default): |
290 | 302 | cache_seconds=cache_seconds, |
291 | 303 | ) |
292 | 304 |
|
293 | | - # Query NTP and set the system RTC. |
294 | | - ntp = adafruit_ntp.NTP( |
295 | | - pool, |
296 | | - server=server, |
297 | | - tz_offset=tz_offset, |
298 | | - socket_timeout=timeout, |
299 | | - cache_seconds=cache_seconds, |
300 | | - ) |
| 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))) |
301 | 308 |
|
302 | | - try: |
303 | | - now = ntp.datetime # struct_time |
304 | | - except OSError as e: |
305 | | - # Retry once in case of transient ETIMEDOUT, after forcing reconnect. |
306 | | - if getattr(e, "errno", None) == 116 or "ETIMEDOUT" in str(e): |
307 | | - # Ensure radio is up again |
308 | | - self.connect() |
309 | | - now = ntp.datetime |
310 | | - else: |
311 | | - raise |
| 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 |
312 | 329 |
|
313 | 330 | if now.tm_year < require_year: |
314 | 331 | raise RuntimeError("NTP returned an unexpected year; not setting RTC") |
|
0 commit comments