ntp-rtc-hora-internet-nanoframework

NTP and RTC Synchronization in nanoFramework

  • 5 min

Time synchronization is the process of adjusting the device’s clock to a reliable source such as NTP or an RTC.

We already have the device connected to Wi-Fi, but we still need to solve an invisible problem: the microcontroller doesn’t know what day it is.

Unlike your computer, which has a small button cell battery (the BIOS battery) to keep time when powered off, most development boards (like the ESP32 DevKit) lose their clock memory on disconnection. When they boot up, they typically revert to a default date (like January 1, 2017).

In this post, we’ll learn how to use the NTP protocol to set our clock. And it’s not just for fun: without the correct time, secure Internet (HTTPS) doesn’t work.

What is NTP?

NTP (Network Time Protocol) is one of the oldest protocols on the Internet. Essentially, it allows our device to ask a master server (like pool.ntp.org or time.google.com) what time it is.

The server responds with the exact UTC time, and our system adjusts its internal clock.

Automatic Synchronization in nanoFramework

The good news is that nanoFramework does the heavy lifting for us. The ESP32’s network stack (based on lwIP) has a built-in NTP client.

If you used WifiNetworkHelper as we saw in the previous lesson, you might already be using it without knowing.

// The 'requiresDateTime: true' parameter forces waiting for NTP
WifiNetworkHelper.ConnectDhcp(
    ssid,
    pass,
    requiresDateTime: true,
    token: new CancellationTokenSource(60000).Token);
Copied!

When we pass true to this parameter, the code blocks and does not continue until:

  1. An IP address is obtained.
  2. The default NTP server is contacted.
  3. The system clock is updated.

Check the Clock Status

We can check if the time is valid simply by looking at the DateTime.UtcNow property.

using System;
using System.Diagnostics;
using System.Threading;

// ...

if (DateTime.UtcNow.Year < 2025)
{
    Debug.WriteLine("Warning! The clock is not synchronized.");
    Debug.WriteLine($"Current system date: {DateTime.UtcNow}");
}
else
{
    Debug.WriteLine("Clock synchronized successfully.");
    Debug.WriteLine($"UTC Time: {DateTime.UtcNow}");
}
Copied!

Remember: NTP always returns UTC (Coordinated Universal Time) time. It knows nothing about daylight saving time or your local time zone.

Waiting for Synchronization

If for some reason you need to force an update (or change the NTP server), you can do so through configuration. However, in most modern versions of nanoFramework for ESP32, this is managed at the native operating system level.

A common practice if you don’t use the Helper is to implement a wait loop:

Debug.WriteLine("Waiting for time synchronization...");

while (DateTime.UtcNow.Year < 2025)
{
    Thread.Sleep(1000);
    // The underlying system keeps trying to connect to NTP in the background
}

Debug.WriteLine("Time obtained!");
Copied!

Internal RTC vs External RTC

Once NTP gives us the time, it is stored in the microcontroller’s internal RTC (Real Time Clock). This clock keeps counting seconds as long as the chip has power.

What happens if I reset?

  • Soft Reset (EN Button): The internal RTC usually retains the time (in certain power modes).
  • Hard Reset (Unplug cable): The RTC loses power and the time is erased. You will have to reconnect to Wi-Fi and request the NTP time again on boot.

External RTC Modules

If your project needs to know the time immediately upon powering on, without waiting for Wi-Fi (or in a place without internet), you will need extra hardware: an RTC module with a battery (like the DS3231 or DS1307) connected via I2C.

In that case, on boot you would read the time from the DS3231 and inject it into the system:

// (Pseudocode with IOT.Device.Rtc driver)
var rtc = new Ds3231(i2cDevice);
Rtc.SetSystemTime(rtc.DateTime); // Update system clock from the battery
Copied!

Time Zones

As we said, DateTime.UtcNow gives us UTC time, which is not the same as London time throughout the year. If you are in Spain and want to display the local time on a screen, you need to add the offset (+1 in winter, +2 in summer).

In “full” .NET we have TimeZoneInfo, which is a giant database with all the time change rules in the world. In nanoFramework, to save memory, we don’t have a complete TimeZoneInfo by default.

You will have to manage it manually:

// Manual example for Spain (Simplified)
DateTime utc = DateTime.UtcNow;
int offset = 1; // Winter

// Very basic logic (does not cover the exact time change in March/October)
// For something robust, there are community NuGet libraries
DateTime localTime = utc.AddHours(offset);

Debug.WriteLine($"Local Time: {localTime}");
Copied!