So, great. Problem is, you can only do it once. After that, the Wifi station is dead. Subsequent calls to the NTP module fail at socket.getaddrinfo, with various combinations of OSError -2 (I can't find a description of any of the special negative error codes that getaddrinfo is admittedly documented to produce) and occasionally -6 (which although also undescribed, I've discovered indicates a closed connection) and 110 (ETIMEDOUT).
Other uses of the Wifi also fail. For example, https://docs.micropython.org/en/latest/ ... k_tcp.html (also buried in the ESP8266 section, curiously, even though the PyBoardD has built-in Wifi and I would expect it to be documented in a more general sense for that reason) has a section "5.2. HTTP GET request" which shows how to build and call a minimal http request. That call works perfectly at any point before I call the NTP module, but just as the NTP module itself will no longer work after it has been called once, this basic web request example also fails at any point after the call to the NTP module.
There must be something about the NTP module that, although running successfully the first time, nevertheless leaves the socket or the station in a bad state.
Here's the code from ntptime.py:
Code: Select all
def time():
NTP_QUERY = bytearray(48)
NTP_QUERY[0] = 0x1B
addr = socket.getaddrinfo(host, 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.settimeout(1)
res = s.sendto(NTP_QUERY, addr)
msg = s.recv(48)
finally:
s.close()
val = struct.unpack("!I", msg[40:44])[0]
return val - NTP_DELTA
BTW, to avoid any possible name collisions between the function above named "time()" and similar functions in the time.py/utime.py modules, I actually renamed that function above in ntptime.py when I copied the file to the PyBoardD flash. So, the error surely has nothing to do with time() being reused.
Something about the code above is "bad socket form". What do you think?
To replicate this simply paste the following into the REPL via ^E paste mode:
Code: Select all
# From micropython/ports/esp8266/modules/ntptime.py with some compaction and function renaming for demo purposes
try:
import usocket as socket
except:
import socket
try:
import ustruct as struct
except:
import struct
def get_ntp_time():
NTP_QUERY = bytearray(48)
NTP_QUERY[0] = 0x1B
addr = socket.getaddrinfo("pool.ntp.org", 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.settimeout(1)
res = s.sendto(NTP_QUERY, addr)
msg = s.recv(48)
finally:
s.close()
val = struct.unpack("!I", msg[40:44])[0]
return val - 3155673600
# From https://docs.micropython.org/en/latest/esp8266/tutorial/network_tcp.html
def http_get(url):
import socket
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
print(str(data, 'utf8'), end='')
else:
break
s.close()
# Connect
import time, network
print("Connecting...")
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(addr, pw) # Obviously, you'll have to fill this in for your own router
while not wlan.isconnected():
pyb.LED(3).on()
time.sleep(.1)
pyb.LED(3).off()
time.sleep(.9)
print("Connected")
# Test http
http_get('http://micropython.org/ks/test.html')
# Query NTP
get_ntp_time()
# At this point, despite the two successful calls just made, the Wifi station is now dead.
# The following calls will fail.
# A soft reset either via ^D or Reset button won't fix the problem.
# Only disconnecting the USB cable will fix the problem.
get_ntp_time()
http_get('http://micropython.org/ks/test.html')