Skip to content

Conversation

mikeysklar
Copy link
Contributor

@mikeysklar mikeysklar commented Sep 1, 2025

Started as Fruit Jam NTP support, but it makes more sense to share NTP support through PortalBase.

adafruit_portalbase/network.py
• Provides NTP-based system clock synchronization.
• Works with both ESP32SPI WiFi coprocessor and native wifi.radio backends.
• Pulls defaults from settings.toml (NTP_SERVER, NTP_TZ, NTP_DST, NTP_RETRIES, NTP_TIMEOUT).
• Includes retry loop with short delays (~0.5s) for reliability with ESP/SPI transport.
• If rtc is available, sets rtc.RTC().datetime.

examples/portalbase_time.py
• New example: minimal demonstration of portal.network.time_sync().

Tested on PyPortal (portalbase is a frozen module). Testing was done with alt lib/ name.

I need to confirm testing on MatrixPortal-M4 and Fruit Jam before merging.

	•	Provides NTP-based system clock synchronization.
	•	Works with both ESP32SPI WiFi coprocessor and native wifi.radio backends.
	•	Pulls defaults from settings.toml (NTP_SERVER, NTP_TZ, NTP_DST, NTP_RETRIES, NTP_TIMEOUT).
	•	Includes retry loop with short delays (~0.5s) for reliability with ESP/SPI transport.
	•	Returns a time.struct_time after syncing.
	•	If rtc is available, sets rtc.RTC().datetime.

examples/portalbase_time.py
	•	New example: minimal demonstration of portal.network.time_sync().
	•	Shows how to:
	1.	Instantiate PyPortal.
	2.	Call portal.network.time_sync().
	3.	Print the synced time (either as struct_time or formatted timestamp).
@mikeysklar
Copy link
Contributor Author

add wait_for_ready() to network.py module. This allows for the ESP co-processor to makes itself presentable. Had been using hard coded delays.

Checking to confirm ESP is ready. Removed hard coded timed waits.

Refactored code into baby helpers to make ruff happy.
add support for:

* MatrixPortal-M4
* Fruit Jam
* MagTag
@ladyada ladyada requested a review from FoamyGuy September 2, 2025 10:56
@mikeysklar
Copy link
Contributor Author

@FoamyGuy - I know you are working on other projects so no rush to review. Just a quick update. I've tested this NTP PR on:

  • Fruit Jam
  • PyPortal

Both running CircuitPython 10-beta3. It ran fine for me.

Since adafruit_portalbase is a frozen library I had to rename the lib for testing purposes on the PyPortal.

I was not able to test on a MatrixPortal-M4 as the frozen portalbase is pulled in by matrixportal and looks like it needs a custom CircuitPython build or some clever trick to load a custom portalbase.

If this NTP is accepted I can go back to adafruit_fruitjam and rip up the NTP and update the examples to avoid redundant code.

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Sep 4, 2025

@mikeysklar Thank you! I will try this out soon.

In order to circumvent frozen libraries you can place the development version in the root of the CIRCUITPY drive. It will import the one from the root of CIRCUITPY if it exists instead of the frozen version.

@mikeysklar
Copy link
Contributor Author

Ah, GTK.

I'll setup a MatrixPortal-M4 with rootdir adafruit_portalbase/ to complete testing on my side and report back.

@b-blake confirmed this PR is working on his Fruit Jam.

@mikeysklar
Copy link
Contributor Author

mikeysklar commented Sep 4, 2025

The local library override worked great. However, I got stuck with the MatrixPortal-M4 testing. I cannot get around the SSL error it is throwing.

Traceback (most recent call last):
  File "code.py", line 1, in <module>
  File "adafruit_matrixportal/matrixportal.py", line 36, in <module>
  File "adafruit_matrixportal/network.py", line 38, in <module>
  File "adafruit_portalbase/wifi_esp32s2.py", line 25, in <module>
ImportError: no module named 'ssl'

MatrixPortal-M4 code.py:

from adafruit_matrixportal.matrixportal import MatrixPortal
portal = MatrixPortal(status_neopixel=None)
net = portal.network
print(net.time_sync())

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Sep 5, 2025

@mikeysklar it looks like for some reason this logic is not determining that it's running on the Matrix Portal M4 https://github.com/adafruit/Adafruit_CircuitPython_MatrixPortal/blob/f6678a77fd52c3538a0b2a2f91dcf05f9a016e05/adafruit_matrixportal/network.py#L35-L38

That is odd. Maybe the sysname could have changed? I'll try it out on my device as well.

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Sep 5, 2025

Indeed it appears that the value returned by os.uname().sysname on the Matrix Portal M4 changed between 9.x and 10.x The new value it returns is samd51j19, which breaks the logic in the Matrix Portal lib. I'll open an issue/PR over there with a fix. But I do think it's a seperate issue unrelated to the time sync specifically.

Your example code from the previous comment works successfully for me on Matrix Portal M4 with 9.2.8 installed.

@mikeysklar
Copy link
Contributor Author

@FoamyGuy - Awesome! I was pulling my hair out over this yesterday. I was certain it was something I was doing wrong.

I'll do one more check on with MagTag and NTP setting and make some cosmetic changes. Don't approve the PR just yet.

@mikeysklar
Copy link
Contributor Author

@FoamyGuy -

Tested with examples/portalbase_time.py on three boards all running CircuitPython-10.0.0-beta3.

  • Fruit Jam
  • PyPortal
  • MagTag

All run clean and sync NTP / RTC with ~4 lines of nearly identical code. If you are okay with it I think this is ready to merge.

Copy link
Contributor

@FoamyGuy FoamyGuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

I tweaked this to make the fruit jam section of code the same as the others

jam = FruitJam(status_neopixel=None)
net = jam.network

I tested that version on Fruit Jam with 10.0.0-beta.3 and it seemed to be working fine.

I think there should be no need to init a new NetworkBase instance because one already gets created internally when FruitJam() init occurs.

@FoamyGuy FoamyGuy merged commit d26e232 into adafruit:main Sep 10, 2025
1 check passed
@FoamyGuy
Copy link
Contributor

Forgot to mention, I also tested after deleting time_sync() from the adafruit_fruitjam library locally on my device to ensure it was using the new code path from this library.

adafruit-adabot pushed a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Sep 11, 2025
@mikeysklar
Copy link
Contributor Author

mikeysklar commented Sep 11, 2025

@FoamyGuy looks good. Thank you for your assistance on this one.

I just formatted a FruitJam and loaded up with the new PortalBase 3.4.0 release from the library bundle. It ran smoothly.

Adafruit CircuitPython 10.0.0-beta.3 on 2025-08-29; Adafruit Fruit Jam with rp2350b
>>>
>>> import storage
>>> storage.erase_filesystem()
% circup install adafruit_portalbase adfaruit_fruitjam
cat <<'EOF' > /Volumes/CIRCUITPY/code.py
# --- Fruit Jam (wrap its WiFi) ---
from adafruit_fruitjam import FruitJam

jam = FruitJam(status_neopixel=None)
net = jam.network


# --- shared output ---
print(net.time_sync())
EOF
Connecting to AP foreverrun
struct_time(tm_year=2025, tm_mon=9, tm_mday=11, tm_hour=17, tm_min=18, tm_sec=19, tm_wday=3, tm_yday=254, tm_isdst=-1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants