-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32: Fix RTC initialization from datetime. #16357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Sebastian Romero <s.romero@arduino.cc>
3fdec81
to
cf0c014
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #16357 +/- ##
==========================================
- Coverage 98.57% 98.53% -0.04%
==========================================
Files 164 164
Lines 21349 21357 +8
==========================================
Hits 21045 21045
- Misses 304 312 +8 ☔ View full report in Codecov by Sentry. |
Update: I also added the possibility to initialize the RTC only with the date. According to the docs the time related parameters are optional.
New test: from time import sleep
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, assert_time = True, 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]}"
if assert_time:
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, ValueError) as e:
if should_fail:
print(f"✅ Test failed as expected: {e}")
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)
try:
rtc.init((year, month, day))
test("init with only date", assert_time=False)
except ValueError as e:
print(f"❌ Test failed: {e}")
try:
print("\nTesting with too many arguments")
rtc.init((year, month, day, hour, minute, second, microsecond, tzinfo, 1234))
print("❌ Test passed but should have failed")
except ValueError as e:
print(f"✅ Test failed as expected: {e}")
try:
print("\nTesting with too few arguments")
rtc.init((year, month))
print("❌ Test passed but should have failed")
except ValueError as e:
print(f"✅ Test failed as expected: {e}")
# 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") Output before the fix:
Output with the fix:
To allow for optional parameters but still checking the required tuple size range I added a new function that checks for the min and max size of the given tuple. I couldn't find an existing test suite for those functions. Any directions? |
Code size report:
|
9dd7761
to
1d5aa24
Compare
Signed-off-by: Sebastian Romero <s.romero@arduino.cc>
02405f5
to
daea17f
Compare
Signed-off-by: Sebastian Romero <s.romero@arduino.cc>
daea17f
to
9afbeb1
Compare
Thanks for the patch, and the comprehensive test. Sorry that you ran into this issue. Indeed the docs don't match the behaviour, although it's not clear which is the "source of truth here" 😅 The mimxrt and samd ports also implement Actually, PR #10607 attempts to fix all the affected ports, and fix some other inconsistencies. So I think that might be a good solution here? |
I should also say that we do eventually want to fix this properly, by making all the methods follow the standard CPython tuple for date-time, namely For this change we either need to define completely new RTC methods that use this CPython tuple format, or wait for MicroPython 2.0. |
The @sebromero would be good to get your test merged, so it can test this feature. And best if it was made generic, for any port, not just esp32. Do you want to attempt that? If not I can take it from here. |
@dpgeorge Sure I can give it a shot. Some guidance needed though:
|
Yes. Pretty much all tests are Python code running on the device (or unix port etc). And that Python code runs the underlying C code and tests it. (One exception: the unix coverage build has
The best way is to use a SKIP mechanism at the start of the test, eg: try:
from machine import RTC
RTC().init(0, 0, 0, 0, 0, 0, 0, 0)
except:
print("SKIP")
raise SystemExit That is a little quirky but lots of other tests do this. Alternatively, for this case you know that the ports that don't conform are try:
from machine import RTC
except:
print("SKIP")
raise SystemExit
import sys
if not hasattr(RTC, "init") or sys.platform in ("pyboard", "renesas-ra"):
print("SKIP")
raise SystemExit You could also use
Not at this stage.
It doesn't really matter. |
Summary
I was pulling my hair out trying to initialize the RTC though its
init
function as follows:However it kept being initialized with a wrong date / time. The documentation states:
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: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:
The output before applying the fix:
The output after applying the fix:
Trade-offs and Alternatives
An alternative could be to change the documentation so that the
init
and thedatetime
function use the same format.tzinfo
doesn't seem to be used anyway. At least not in this port.