Using ntptime.settime() while _thread is running can break sleep timing
Port, board and/or hardware
Raspberry Pi PICO W
MicroPython version
MicroPython v1.23.0 on 2024-06-02; Raspberry Pi Pico W with RP2040
Reproduction
- _thread_work() - measure how long time.sleep takes
- wifi() - connect to wifi and reconnect if it does down
- wifi_auth just has the wifi login variables
- setTime() - this sets the clock using ntptime
- this was unreliable in micropython 1.2, hence the try blocks
- wait4clock() - just some busy work for asyncio, can be used to start process that depend on the clock being set
import _thread
import ntptime
import asyncio
import time
sleep=asyncio.sleep_ms
#ntptime.host="10.0.0.69"
wlan = 0
def _thread_work():
while 1:
then=time.ticks_ms()
time.sleep(1)
then=time.ticks_diff(time.ticks_ms(),then)
print("Core 1:",then)
async def wifi():
from wifi_auth import ssid, password
import network
global wlan
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.config(pm = 0xa11140)# Power management is very very bad, ping time is around 1000x worse and packet loss insane
wlan.connect(ssid, password)
while 1:
while 1:
wstat=wlan.status()
if wstat < 0 or wstat >= 3:
break
print('Waiting for WiFi connection...')
await sleep(1000)
if wlan.status() == 3:
status = wlan.ifconfig()
print('Wifi Connected; ip =',status[0])
while wlan.isconnected():
await sleep(30000)
print('WiFi Down')
else:
print("Failed to connect to wifi; retry in 30 seconds")
await sleep(30000)
wlan.connect(ssid, password)
#END wifi()
async def setTime():
#ntptime.settime() failure: [Errno 110] ETIMEDOUT
#ntptime.settime() failure: overflow converting long int to machine word
print('Attempt to set time')
success=0
try:
print("calling ntptime.settime()")
ntptime.settime()
success=1
except OverflowError:
# it is not going to work
print("overflow error; settime is borked")
except OSError:
print("ntptime.settime() failure")
if not success:
await sleep(10000)
asyncio.create_task(setTime())
else:
print("END of setTime() process")
#END setTime()
async def wait4clock():
delay=2000
while time.time() < 1640995200: # Wait for clock to set or a 1 year...)
print("Waiting for clock...")
await sleep(3000)
print('Clock set:',time.time())
#_thread.start_new_thread(_thread_work,())
#END wait4clock()
async def main():
asyncio.create_task(wait4clock())
asyncio.create_task(wifi())
while not wlan or not wlan.isconnected():
then=time.ticks_ms()
await sleep(1000)
then=time.ticks_diff(time.ticks_ms(),then)
print("Core 0:",then,"Waiting for wifi")
asyncio.create_task(setTime())
while 1:
then=time.ticks_ms()
await sleep(1000)
then=time.ticks_diff(time.ticks_ms(),then)
print("Core 0:",then)
_thread.start_new_thread(_thread_work,())
asyncio.run(main())
Expected behaviour
Calls to time.sleep(1) and asyncio.sleep_ms(1000) should be near 1 second long
Observed behaviour
output of example code:
Waiting for clock...
Waiting for WiFi connection...
Core 1: 1000
Core 0: 1000 Waiting for wifi
Waiting for WiFi connection...
Core 1: 1000
Core 0: 1001 Waiting for wifi
Waiting for WiFi connection...
Core 1: 1000
Waiting for clock...
Core 0: 1003 Waiting for wifi
Wifi Connected; ip = 10.0.0.190
Core 1: 1000
Core 0: 1001 Waiting for wifi
Attempt to set time
calling ntptime.settime()
END of setTime() process
Core 1: 22526
Core 0: 22522
Clock set: 1728875328
Core 1: 5324
Core 0: 5324
Core 1: 7473
Core 0: 7474
Core 1: 17208
Core 0: 17208
Core 1: 5319
Core 0: 5319
Core 1: 24678
Core 0: 24678
Core 1: 5325
Core 0: 5325
Core 1: 24678
Core 0: 24678
Core 1: 5330
Core 0: 5330
Core 1: 24673
Core 0: 24673
Core 1: 5325
Core 0: 5325
Core 1: 24684
Core 0: 24684
Core 1: 5319
Core 0: 5319
Core 1: 24682
Core 0: 24683
Core 1: 5324
Core 0: 5324
Core 1: 1939
Core 0: 1939
Core 1: 5734
Core 0: 5734
Core 1: 5836
Core 0: 5836
Core 1: 11162
Core 0: 11162
Core 1: 5329
Core 0: 5330
Core 1: 7059
Core 0: 7059
Core 1: 13925
Core 0: 13926
Core 1: 3687
Core 0: 3687
Core 1: 5325
Core 0: 5325
Core 1: 7269
Core 0: 7269
Core 1: 17413
Core 0: 17413
Core 1: 5325
Core 0: 5325
Core 1: 1018
Core 0: 1018
Core 1: 23655
Core 0: 23655
Core 1: 5324
Core 0: 5324
Additional Information
- Note this does not have a 100% reproduction rate, feels near 50%
- This is a regression since micropython 1.2 (rp2-pico-w-20230426-v1.20.0.u2f)
- Note that Thonny is set to NOT synchronize device's real time clock (Tools -> Options-> Interpreter)
Code of Conduct
Yes, I agree
RP2: machine.RTC().datetime() does not advance during lightsleep
Port, board and/or hardware
Raspberry Pi Pico W and Raspberry Pi Pico 2 W
MicroPython version
All versions starting with v1.24.0 (including recently released v1.26.0)
Reproduction
- Copy code below to Pico and name it "main.py"
- Reset the Pico and allow the code to complete (approx 5 seconds). No repl needed as the code writes a log file to the flash storage
- Connect the Pico to the USB port and inspect the file "local.log" on the Pico
Code used to test:
# Test RTC sleep behaviour
import machine, os, time
SLEEP_MS = const(2000)
def write_log(s: str) -> None:
dt = machine.RTC().datetime()
log_text = f"[RTC={dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d} ticks={time.ticks_ms()}] {s}"
with open("local.log", "a") as file:
file.write(log_text + "\n")
write_log(f"Machine = '{os.uname()[4]}'")
write_log(f"Version = '{os.uname()[3]}'")
time.sleep_ms(SLEEP_MS)
write_log(f"After time.sleep_ms({SLEEP_MS})")
machine.lightsleep(SLEEP_MS)
write_log(f"After machine.lightsleep({SLEEP_MS})")
Expected behaviour
The real time clock should advance by 2 seconds after running 'machine.lightsleep(2000)' like it was on micropython versions up to and including 1.23.0. Example output from 1.23.0:
[RTC=00:00:01 ticks=49] Machine = 'Raspberry Pi Pico W with RP2040'
[RTC=00:00:01 ticks=54] Version = 'v1.23.0 on 2024-06-02 (GNU 13.2.0 MinSizeRel)'
[RTC=00:00:03 ticks=2058] After time.sleep_ms(2000)
[RTC=00:00:05 ticks=4065] After safe_sleep(2000) with 0 early wakeups
Observed behaviour
The real time clock does not advance during machine.lightsleep(2000) as shown below running on 1.26.0:
[RTC=00:00:01 ticks=36] Machine = 'Raspberry Pi Pico W with RP2040'
[RTC=00:00:01 ticks=42] Version = 'v1.26.0 on 2025-08-09 (GNU 14.2.0 MinSizeRel)'
[RTC=00:00:03 ticks=2033] After time.sleep_ms(2000)
[RTC=00:00:03 ticks=4037] After machine.lightsleep(2000)
Additional Information
While machine.RTC().datetime() does not advance during machine.lightsleep(), time.ticks_ms advances as expected.
Code of Conduct
Yes, I agree