ntptime kills the wifi station, hard reset required to fix

The official PYBD running MicroPython, and its accessories.
Target audience: Users with a PYBD
User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: ntptime kills the wifi station, hard reset required to fix

Post by pythoncoder » Tue Apr 20, 2021 12:36 pm

davef wrote:
Fri Apr 16, 2021 10:17 pm
...
Is that -3155673600 indicative of the problem? Actually after trying this a few more times it seems if I don't wait more than one (?) second between tries then I get the error...
If you look at ntptime.py you'll find this line. A return value of -3155673600 means that the time() function has failed, msg was not updated, so the final subtraction returns -NTP_DELTA.

I think the settime() function is buggy as it doesn't cater for this case. You might rewrite it as follows:

Code: Select all

def settime():
    t = time()
    if t < 0:
        return False
    import machine
    import utime

    tm = utime.gmtime(t)
    machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0))
    return True
You could then detect failure in your code and take remedial action (wait a few seconds and try again?).

I have raised this issue against ntptime as this is surely a bug.
Peter Hinch
Index to my micropython libraries.

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ntptime kills the wifi station, hard reset required to fix

Post by davef » Tue Apr 20, 2021 7:55 pm

Hi Peter,

Thanks heaps for identifying what hopefully is the cause of ntptime freezing in my system.
You might rewrite it as follows:
:)
I would really like to be able to rewrite, add, change source code and re-build. Latest effort here viewtopic.php?f=2&t=9886.

I am planning to set-up a new 64-bit machine for my Micropython work, but first I will buy a bunch of NodeMCU's as suggested in the thread.

Appreciate your efforts towards sorting out my issues.

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ntptime kills the wifi station, hard reset required to fix

Post by davef » Fri Apr 23, 2021 7:09 pm

Have not seen any failures at settime() with your code modification ... on an ESP8266.

The random error I still get on the modified ESP8266 and the stock ESP32 firmware is:

Code: Select all

[Errno 110] ETIMEOUT
Does not the 110 indicate an error thrown by the ESP operating system?

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ntptime kills the wifi station, hard reset required to fix

Post by kevinkk525 » Mon May 03, 2021 10:13 am

The error still persists on the pyboard-D with micropython 1.15... Any way to solve this? The first ntptime.time() works succesfully, afterwards no connection works anymore and it needs a hard reset.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ntptime kills the wifi station, hard reset required to fix

Post by davef » Mon May 03, 2021 10:34 am

I can still get up to 5 fails on ntptime.time()

Here is what I do:

Code: Select all

def getntptime():
    now = 0
#    ntptime.host = 'nz.pool.ntp.org'
    count = 0

    while (count < 5):
        count += 1

        try:
            now = ntptime.time()
        except OSError as error:
            try:
                with open('errors.txt', 'a') as outfile:
                    outfile.write('ntptime.time() failed with now = ' + str(now) + '\n')
            except OSError:
                pass

        print('.', end = '')
        utime.sleep(1)

        if (now > 660000000):
            count = 0
            break

    if (count == 5):
        count = 0

        try:
            with open('errors.txt', 'a') as outfile:
                outfile.write('ntptime.time() failed 5 times' + '\n')
        except OSError:
            print('oops')

        machine.reset()

    print(' got epoch time')
    utime.sleep(1)
Those 5 fails will be now = 0

The 660000000 is just a "recent time". Probably you could say "as long as now != 0" you have a valid epoch time.

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ntptime kills the wifi station, hard reset required to fix

Post by kevinkk525 » Mon May 03, 2021 10:35 am

I don't have an epoch problem on the pyboard-D. The first sync works and after that I can't connect anywhere anymore. No socket will work, all connection attempts time out.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ntptime kills the wifi station, hard reset required to fix

Post by davef » Mon May 03, 2021 10:48 am

We need to hear from kwiley!

greentree
Posts: 15
Joined: Wed Dec 16, 2015 3:16 am

Re: ntptime kills the wifi station, hard reset required to fix

Post by greentree » Fri May 20, 2022 3:17 pm

Has anyone made progress on this issue?

I've encountered similar flakiness with ntptime.py (borrowed as above from the ESP8266 port) using MicroPython v1.18 on a PYBD-SF2W.

However, a hard reboot to reset the wifi seems at this point unnecessary.

I've set

Code: Select all

        s.settimeout(10)
        #s.settimeout(1)
in ntptime.py. Using test code

Code: Select all

from network import WLAN, STA_IF, AP_IF
from time import sleep_ms
import ntptime

ap = WLAN(AP_IF) # create access-point interface
ap.active(False)         # deactivate the interface

sleep_interval = 500

stats = [0,0,0,0]
success = [0,0]

wlan = WLAN(STA_IF)
sleep_ms(sleep_interval)
wlan.active(True)
sleep_ms(sleep_interval)
wlan.connect(ssid, passwd)
sleep_ms(sleep_interval)

for i in range(100):
    try:
        status_before = wlan.status()
        t=ntptime.time()
        status_after = wlan.status()
        print(i,status_before,status_after,t)
        success[1] += 1
    except Exception as ex:
        status_after = wlan.status()
        print(i,status_before,status_after,'ntptime error:',ex)
        success[0] += 1
    finally:
        stats[status_after] += 1
        sleep_ms(sleep_interval)
wlan.disconnect()
wlan.deinit()

print('\n\nSuccess results:')
print(success)
print('Status results:')
print(stats)
gives results like

Code: Select all

0 1 1 ntptime error: [Errno 113] EHOSTUNREACH
1 1 1 ntptime error: [Errno 113] EHOSTUNREACH
2 1 1 ntptime error: [Errno 113] EHOSTUNREACH
3 1 1 ntptime error: [Errno 113] EHOSTUNREACH
4 1 1 ntptime error: [Errno 113] EHOSTUNREACH
5 2 2 ntptime error: [Errno 113] EHOSTUNREACH
6 3 3 ntptime error: [Errno 110] ETIMEDOUT
7 3 3 706373344
8 3 3 706373345
9 3 3 706373345
10 3 3 706373346
11 3 3 706373347
12 3 3 706373347
13 3 3 706373348
14 3 3 ntptime error: [Errno 110] ETIMEDOUT
15 3 3 706373359
16 3 3 706373360
and

Code: Select all

Success results:
[21, 79]
Status results:
[0, 5, 1, 94]
The EHOSTUNREACH errors almost always occur at the start, with wlan.status<3, so this error could be easily circumvented.

ETIMEDOUT errors do not seem predictable from wlan.status.

Does anyone have insight into the root cause of these errors? If not, error handling like the above may be adequate for my application at least.

davef
Posts: 811
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: ntptime kills the wifi station, hard reset required to fix

Post by davef » Fri May 20, 2022 7:30 pm

Without reading through the whole thread the following has been working for me for the last year:

Code: Select all

try:
    import usocket as socket
except:
    import socket
try:
    import ustruct as struct
except:
    import struct
import utime
import machine


# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600

# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org'
host = "pool.ntp.org"


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)
    counter = 0

 #  try 5 times to get the time
    while True:
        counter +=1

        try:
            s.settimeout(10) #  was 1 second
            res = s.sendto(NTP_QUERY, addr)
            msg = s.recv(48)
            counter = 0
            s.close()
            break
        except Exception:
            try:
                with open('errors.txt', 'a') as outfile:
                    outfile.write('getting the time failed' + '\n')
            except OSError:
                pass

        utime.sleep(50)

        if counter == 5:
            counter = 0
            machine.reset()

    val = struct.unpack("!I", msg[40:44])[0]
    return val - NTP_DELTA


# There's currently no timezone support in MicroPython, and the RTC is set in UTC time.
def settime():
    t = time()
    if t < 0:
        return False
    import machine
    import utime

    tm = utime.gmtime(t)
    machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0))
line 32 set to 10 seconds
line 45 for a situation where it doesn't matter if it takes a few minutes to get the time.
line 57 and 58 a modification by Peter Hinch

greentree
Posts: 15
Joined: Wed Dec 16, 2015 3:16 am

Re: ntptime kills the wifi station, hard reset required to fix

Post by greentree » Sat May 21, 2022 2:37 pm

@davef, thanks for sharing that code. I'll add Peter Hinch's fix to settime.

In my application, NTP is only correcting the DS3231 RTC, which is pretty accurate for long periods, but battery life is limiting. So having time resets work only some of the time is less problematic than long delays during NTP queries. But it's helpful to see your strategy.

Have you tried setting the timeout to longer (e.g. 50 s) instead of having an interval between attempts?

Post Reply