feat: Enhance NTP synchronization with timeout and error handling
This commit is contained in:
parent
99d92a6e90
commit
b018b427f6
91
main.py
91
main.py
@ -1,4 +1,4 @@
|
|||||||
from machine import Pin, WDT # type: ignore
|
from machine import Pin, RTC # type: ignore
|
||||||
import time # type: ignore
|
import time # type: ignore
|
||||||
import network # type: ignore
|
import network # type: ignore
|
||||||
import json
|
import json
|
||||||
@ -141,23 +141,60 @@ if wifi and wifi.isconnected():
|
|||||||
print(f"Web Interface: http://{ifconfig[0]}")
|
print(f"Web Interface: http://{ifconfig[0]}")
|
||||||
print("="*50 + "\n")
|
print("="*50 + "\n")
|
||||||
|
|
||||||
# Send startup notification to Discord
|
# Send startup notification to Discord (with timeout, non-blocking)
|
||||||
send_discord_message(f"Pico W online at http://{ifconfig[0]} ✅")
|
try:
|
||||||
|
success = send_discord_message(f"Pico W online at http://{ifconfig[0]} ✅")
|
||||||
|
if success:
|
||||||
|
print("Discord startup notification sent")
|
||||||
|
else:
|
||||||
|
print("Discord startup notification failed (continuing anyway)")
|
||||||
|
except Exception as e:
|
||||||
|
print("Discord notification error: {}".format(e))
|
||||||
|
|
||||||
# Start web server early so page can load even if time sync is slow
|
# Start web server early so page can load even if time sync is slow
|
||||||
web_server = TempWebServer(port=80)
|
web_server = TempWebServer(port=80)
|
||||||
web_server.start()
|
web_server.start()
|
||||||
|
|
||||||
# Attempt time sync non-blocking (short timeout + retry flag)
|
# Attempt time sync with timeout (MicroPython compatible)
|
||||||
ntp_synced = False
|
ntp_synced = False
|
||||||
try:
|
try:
|
||||||
import ntptime # type: ignore
|
import ntptime # type: ignore
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
# Monkey-patch ntptime.time() to add timeout
|
||||||
|
original_time_func = ntptime.time
|
||||||
|
|
||||||
|
def time_with_timeout():
|
||||||
|
"""NTP time fetch with 3-second timeout."""
|
||||||
|
NTP_DELTA = 2208988800
|
||||||
|
host = "pool.ntp.org"
|
||||||
|
NTP_QUERY = bytearray(48)
|
||||||
|
NTP_QUERY[0] = 0x1B
|
||||||
|
|
||||||
|
# Create socket with timeout
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.settimeout(3.0) # 3-second timeout
|
||||||
|
|
||||||
|
try:
|
||||||
|
addr = socket.getaddrinfo(host, 123)[0][-1]
|
||||||
|
s.sendto(NTP_QUERY, addr)
|
||||||
|
msg = s.recv(48)
|
||||||
|
s.close()
|
||||||
|
val = struct.unpack("!I", msg[40:44])[0]
|
||||||
|
return val - NTP_DELTA
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
# Use patched version
|
||||||
|
ntptime.time = time_with_timeout
|
||||||
ntptime.settime()
|
ntptime.settime()
|
||||||
ntp_synced = True
|
ntp_synced = True
|
||||||
print("Time synced with NTP server")
|
print("Time synced with NTP server")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Initial NTP sync failed: {}".format(e))
|
print("Initial NTP sync failed: {}".format(e))
|
||||||
# Will retry later in loop
|
print("Will retry in background...")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# WiFi connection failed
|
# WiFi connection failed
|
||||||
@ -320,18 +357,40 @@ while True:
|
|||||||
|
|
||||||
# Retry NTP sync every ~10s if not yet synced
|
# Retry NTP sync every ~10s if not yet synced
|
||||||
if not ntp_synced and retry_ntp_attempts < max_ntp_attempts:
|
if not ntp_synced and retry_ntp_attempts < max_ntp_attempts:
|
||||||
# Try once immediately, then whenever (time.time() % 10) < 1 (rough 10s window)
|
if retry_ntp_attempts == 0 or (time.time() % 10) < 1:
|
||||||
try:
|
try:
|
||||||
import ntptime # type: ignore
|
import ntptime # type: ignore
|
||||||
if retry_ntp_attempts == 0 or (time.time() % 10) < 1:
|
import socket
|
||||||
ntptime.settime()
|
import struct
|
||||||
ntp_synced = True
|
|
||||||
print("NTP sync succeeded on retry #{}".format(retry_ntp_attempts + 1))
|
# Quick NTP sync with timeout
|
||||||
except Exception as e:
|
NTP_DELTA = 2208988800
|
||||||
# Increment only when an actual attempt was made
|
host = "pool.ntp.org"
|
||||||
if retry_ntp_attempts == 0 or (time.time() % 10) < 1:
|
NTP_QUERY = bytearray(48)
|
||||||
|
NTP_QUERY[0] = 0x1B
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.settimeout(3.0) # 3-second timeout
|
||||||
|
|
||||||
|
try:
|
||||||
|
addr = socket.getaddrinfo(host, 123)[0][-1]
|
||||||
|
s.sendto(NTP_QUERY, addr)
|
||||||
|
msg = s.recv(48)
|
||||||
|
val = struct.unpack("!I", msg[40:44])[0]
|
||||||
|
t = val - NTP_DELTA
|
||||||
|
|
||||||
|
tm = time.gmtime(t)
|
||||||
|
RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0))
|
||||||
|
|
||||||
|
ntp_synced = True
|
||||||
|
print("NTP sync succeeded on retry #{}".format(retry_ntp_attempts + 1))
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
retry_ntp_attempts += 1
|
retry_ntp_attempts += 1
|
||||||
print("NTP retry {} failed: {}".format(retry_ntp_attempts, e))
|
print("NTP retry {} failed: {}".format(retry_ntp_attempts, e))
|
||||||
|
|
||||||
# Enable garbage collection to free memory
|
# Enable garbage collection to free memory
|
||||||
gc.collect()
|
gc.collect()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user