ESP32/Living on a network/46. mDNS and NTP
Your chip
Your language
Living on a network · 46 of 81

mDNS and NTP

Two small problems that always arrive together - what to call the board when its IP address keeps changing, and what time it thinks it is, given that it starts at midnight on 1 January 1970.

/esp32/mdns-and-ntp · arduino · S3

How wrong the clock gets

the chip's internal RC · ±5000 ppm
432 s out
What keeps time between syncs
Time since the last sync24 h
Error
7.2 min
Good enough for a log
no
7.2 minutes out, and the timestamps in your log are now fiction. Re-sync: configTime() already installs a periodic update, so the fix is usually to stop disabling it. On a battery device that deep-sleeps, sync once a day — one NTP exchange is a few hundred bytes.

mDNS in one paragraph

The board shouts its name onto the local network and answers when somebody asks for it. No server, no configuration, no DNS entry. MDNS.begin("greenhouse") makes it greenhouse.local for anything on the same network that speaks mDNS — which is macOS, iOS, Windows 10 and later, and Linux with Avahi. Android is the gap.

Time on a sleeping device

Deep sleep stops the CPU but the RTC keeps counting, so the time survives. A power cut does not. Sync once at boot and once a day; one NTP exchange is a few hundred bytes and a few tens of milliseconds of radio, which is nothing against the wake-up it rides along with.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

Four lines for a name, two for a clock. configTime also installs a periodic re-sync, which is the part that keeps a long-running device honest.

name_and_time.ino
#include <WiFi.h>
#include <ESPmDNS.h>
#include <time.h>

void setup() {
  Serial.begin(115200);
  WiFi.begin("your-network", "your-password");
  while (WiFi.status() != WL_CONNECTED) delay(250);

  if (MDNS.begin("greenhouse")) {          // now greenhouse.local
    MDNS.addService("http", "tcp", 80);
  }

  // Europe/London, with daylight saving handled by the rule
  configTzTime("GMT0BST,M3.5.0/1,M10.5.0", "pool.ntp.org", "time.nist.gov");

  struct tm t;
  if (getLocalTime(&t, 10000)) {
    Serial.println(&t, "%Y-%m-%d %H:%M:%S");
  } else {
    Serial.println("no time yet - carrying on anyway");
  }
}

void loop() {}

getLocalTime blocks until the first sync arrives or the timeout expires. Give it a real timeout - a board with no internet must still run.

When it does not work

greenhouse.local works on the Mac and not on Android

Android's mDNS support has been patchy for years. Keep the IP address as a fallback, and print it on a display or over serial.

The clock is right at boot and hours out a week later

The internal RC oscillator drifts by thousands of parts per million. Re-sync periodically, or fit a crystal-backed RTC module for anything that must keep time offline.

Timestamps are one hour out half the year

You set an offset instead of a time zone. configTzTime with a POSIX rule handles daylight saving automatically. A fixed offset cannot.

The board hangs at boot when the internet is down

getLocalTime with no timeout, or a blocking NTP call. Give both a timeout and continue - a thermostat that shows the temperature with the wrong clock is far better than one that shows nothing.

Where this goes next

The sync lands. Turning that one number into a date, in the right timezone, with daylight saving handled for you.

Keeping time with time.h

Edit this page — content/esp32/mdns-and-ntp.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum