← index #3674PR #16357
Duplicate · high · value 5.353
QUERY · ISSUE

ESP32 machine.rtc datetime tuple parameters don't match documentation

openby ed-frenchopened 2018-03-19updated 2024-09-19
docsport-esp32

Micropython documentation: http://docs.micropython.org/en/latest/wipy/library/machine.RTC.html
Shows machine.rtc.init documented with tuple like this:

RTC.init(datetime)
Initialise the RTC. Datetime is a tuple of the form:

(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])

However, the code suggests a different order is used: https://github.com/micropython/micropython/blob/master/ports/esp32/machine_rtc.c

timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]))

Likewise with machine.rtc.datetime actually returns this order of parameters in the tuple:

r.datetime()
(2018, 3, 21, 2, 6, 8, 19, 258907)
r.datetime()
(2018, 3, 21, 2, 6, 8, 22, 828728)
r.datetime()
(2018, 3, 21, 2, 6, 9, 31, 888997)
r.init((2018,3,19,0,7,5,0,0))
r.datetime()
(2018, 3, 19, 0, 7, 5, 4, 368663)
r.datetime()
(2018, 3, 19, 0, 7, 5, 16, 608804)
r.datetime()
(2018, 3, 19, 0, 7, 5, 38, 98816)

CANDIDATE · PULL REQUEST

esp32: Fix RTC initialization from datetime.

openby sebromeroopened 2024-12-04updated 2025-01-28
port-esp32

Summary

I was pulling my hair out trying to initialize the RTC though its init function as follows:

rtc = RTC()

year = 2024
month = 12
day = 26
weekday = 3
hour = 6
minute = 30
second = 20
microsecond = 0
tzinfo = 0

rtc.init((year, month, day, hour, minute, second, microsecond, tzinfo))

However it kept being initialized with a wrong date / time. The documentation states:

Initialise the RTC. Datetime is a tuple of the form:
(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]

The problem lies in the fact that both the datetime setter and init use the same helper function. The 8-tuple for that one is different though according to the docs:

The 8-tuple has the following format:
(year, month, day, weekday, hours, minutes, seconds, subseconds)

It uses weekday which makes sense as the getter should deliver this information and both setter and getter shall use the same format. Now we can see that using the same helper function for both formats cannot work and the two need to be distinguished. This is what this PR does. It fixes the issue by treating the two differently.

Testing

I tested the fix on an Arduino Nano ESP32. I wasn't sure where to add a unit test, but here is what I wrote in MicroPython:

from machine import RTC

rtc = RTC()

year = 2024
month = 12
day = 26
weekday = 3
hour = 6
minute = 30
second = 20
microsecond = 0
tzinfo = 0

def test(source, should_fail=False):
    print(f"\nTesting {source}")
    # Read time
    t = rtc.datetime()
    print(t)
    try:
        assert t[0] == 2024, f"Year should be 2024 but was {t[0]}"
        assert t[1] == 12, f"Month should be 12 but was {t[1]}"
        assert t[2] == 26, f"Day should be 26 but was {t[2]}"
        assert t[3] == 3, f"Weekday should be 3 but was {t[3]}"
        assert t[4] == 6, f"Hour should be 6 but was {t[4]}"
        assert t[5] == 30, f"Minute should be 30 but was {t[5]}"
        assert t[6] == 20, f"Second should be 20 but was {t[6]}"
        if should_fail:
            print("❌ Test should have failed but didn't")
        else:
            print("✅ Test passed")
    except AssertionError:
        if should_fail:
            print("✅ Test failed as expected")
        else:
            print("❌ Test passed but should have failed")


# Initialise the RTC. Datetime is a tuple of the form:
# (year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]
rtc.init((year, month, day, hour, minute, second, microsecond, tzinfo))
test("init in order")

rtc.init((year, month, day, tzinfo, hour, minute, second, microsecond))
test("init out of order", should_fail=True)

# The 8-tuple has the following format:
# (year, month, day, weekday, hours, minutes, seconds, subseconds)
rtc.datetime((year, month, day, weekday, hour, minute, second, microsecond))
test("datetime in order")

The output before applying the fix:

Testing init in order
(2024, 12, 27, 4, 6, 20, 0, 373)
❌ Test passed but should have failed

Testing init out of order
(2024, 12, 26, 3, 6, 30, 20, 245)
❌ Test should have failed but didn't

Testing datetime in order
(2024, 12, 26, 3, 6, 30, 20, 256)
✅ Test passed

The output after applying the fix:

Testing init in order
(2024, 12, 26, 3, 6, 30, 20, 389)
✅ Test passed

Testing init out of order
(2024, 12, 26, 3, 0, 6, 30, 365)
✅ Test failed as expected

Testing datetime in order
(2024, 12, 26, 3, 6, 30, 20, 235)
✅ Test passed

Trade-offs and Alternatives

An alternative could be to change the documentation so that the init and the datetime function use the same format. tzinfo doesn't seem to be used anyway. At least not in this port.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied