Skip to content

Repository files navigation

ESP32 NTP Stratum 1 Time Server (version 3.0.2)

An ESP32 NTP Stratum 1 Time Server for your home network

License: MIT


Overview

This project was born with a simple goal: create a low-budget, Stratum 1 NTP time server solution with no need for periodic Linux OS updates. Rather just set it up and let it do its job.

ESP32 Time Server

It uses a GNSS (North America & Europe) receiver as its time source, making it a true Stratum 1 server — meaning it gets its time directly from satellites rather than from another NTP server. Every device on your home network can then synchronize to it for highly accurate local time.


What's New

Current Version (3.0+)

  • NTPv4 Symmetric-key authentication added for Windows clients using Meinberg and Linux clients using chrony. For more information, please see this document.
  • WS2182 RGB LED support added (KY-016 support continues)

Version 2 was a ground-up rewrite which came with a faster, more capable board support and a long list of accuracy, reliability, and convenience improvements over version 1, including:

  • Higher accuracy, lower jitter — full use of the GPS module's PPS (Pulse Per Second) pin disciplines the clock for sub-millisecond accuracy, with hardware time stamping and RFC 9769-compatible interleaved responses further reducing jitter for both NTPv3 and NTPv4 requests.
  • Faster, more modern hardware — built around the WaveShare ESP32-P4-ETH (or the newer ESP32-P4-WIFI6-ETH), a significant step up from the ESP32-WROOM-32/32E used in v1.
  • Broader GNSS module support — still works great with the recommended SparkFun MAX-M10S, but also supports lower-cost generic GNSS modules and now has experimental support for the GT-U16, which offers better reception than some competing receivers at the same or higher price points.
  • Wireless firmware updates — Over-the-Ethernet OTA updates let you push new firmware directly from VS Code, with on-screen progress shown on the LCD, so you rarely need to plug in a cable after the first flash.
  • Handles more traffic — greatly increased throughput and concurrent request handling, so the server keeps up even on busy networks.
  • IPv6 support — the server now responds to NTP requests over IPv6 as well as IPv4.
  • Flexible networking — set a custom MAC address or a static IP, instead of always relying on the device's default address and DHCP.
  • Optional LCD support — a 4x20 LCD screen was required in v1; in v2 it's entirely optional, along with an optional up time / reset button.
  • Optional RGB LED support added — here is how that is used.
  • Smart GNSS lock tracking — improved satellite lock and PPS discipline tracking, with results correctly reported as Stratum 16 (undefined) if lock or discipline is temporarily lost, and automatic recovery once it's restored.
  • Quick restarts — GPS module identity and baud rate are saved to non-volatile storage, so the server starts up quickly after the initial setup.
  • MQTT publishing — optionally publish time server stats to an MQTT broker, with TF card support for queueing far more messages if the broker connection drops.
  • Home Assistant integration — ready-made entity and dashboard setup instructions for pulling time server stats into Home Assistant.
  • Built-in self-test — an optional startup health check lets the server verify its own core functionality every time it boots.
  • Testing tools and guidance — instructions, tools, and links for measuring jitter, drift, RFC 9769 compliance, memory usage, and server performance under stress.
  • Updated 3D printed case — enclosure files refreshed for the new WaveShare ESP32-P4-ETH board.

Version 1 described in detail here was built for Arduino / PlatformIO and remains available here.

(Detailed release history)


Hardware

Qty Item
1 WaveShare ESP32-P4-ETH or ESP32-P4-WIFI6-ETH development board (with or without optional PoE) 1 2
1 GPS/GNSS module Recommended: SparkFun GNSS Receiver Breakout - MAX-M10S (Qwiic) 2. Additionally, experimental support for the GT U16 has been added in version 2.9 - this receiver offers superior reception when coupled with the right antenna (see notes below). Additionally, while some lower-cost generic modules UBlox compliant receivers are supported, those without a PPS pin are no longer supported.
1 GPS/GNSS antenna with SMA connector (SparkFun GPS/GNSS Magnetic Mount Antenna - 3m (SMA)) 2. Alternatively the GT U16 with an L1/L5 antenna offers superior reception. However, in my testing I used the 3M SMA W70C L1/L2/L5 antenna an IPEX to SMA adapter and got very good results (I have the antenna bundled with the GT U16 (link above) on order and when I get it and test it I will update this page).
1 (Optional) TF Card, formatted as FAT32, if you're using MQTT and want more than four messages queued should broker communications be down) 2
1 (Optional) RGB LED: KY-016 (AliExpress) or WS2812 (AliExpress) with a 470Ω resistor and optional lens cap (AliExpress)
1 (Optional) 4×20 I²C LCD display with HD44780 controller with PCF8574 I²C backpack (AliExpress) 2
1 (Optional) Momentary push button for displaying up time and triggering a reset (AliExpress) 2
1 (Optional) USB C extension cable (with right angle end) (AliExpress) 2 + two M3*8
— Miscellaneous: Ethernet cable, female dupont connection wires, small 4" .1" zip ties, solder 2
— A PoE-capable switch, PoE injector, or USB-C power supply and USB-C cable

⚠️ WARNING — Do NOT power the ESP32-P4-POE-ETH or the ESP32-P4-WIFI6-POE-ETH via both its USB-C connector and a PoE powered Ethernet cable at the same time. Powering from both simultaneously may damage the ESP32-P4-ETH board, POE switch, or device providing USB power. Either power source alone is sufficient to power the board, GPS module, and LCD screen.

1 See notes in the 'What's New in Version 2' section above.

2 (Optional) there are 3D Printable Case designed for use with ESP32-P4_ETH and these specific components (for more information see below).

(Also Optional) To cut down on wiring a PCB can be used. One designed to work within this project's 3D printed enclosure is available in the PCB folder. If your interested, please review the Readme.md file in that folder for more information.

Wiring

GPS module → ESP32-P4-ETH (mandatory)

GPS pin ESP32-P4-ETH pin
GND GND
VCC 3V3
PPS GPIO 20
TXD GPIO 21 (RX)
RXD GPIO 22 (TX)

Pro Tip: (Optionally) Adding a capacitor between the GNSS module's Vcc and GND power pins, placed as close as possible to those pins, can improve GNSS power supply stability. Use a 100nf (aka 0.1μf, aka 104) ceramic capacitor, rated at least 50v, such as this one.

Important:

Some GNSS receivers and breakout boards provide a 3.3v PPS (Pulse-Per-Second) output pin while others provide a 5v PPS output pin.

  1. Only connect a 3.3v PPS pin to an ESP32 GPIO pin, never connect a 5v PPS pin to an ESP32 GPIO pin

  2. For the wire between the ESP32-P4's GPIO pin and the GNSS Receiver's PPS pin use as short and as well connect wire as possible; a standard copper Dupont wire will be fine assuming its gauge is between 24 AWG and 28 AWG

  3. The GNSS GND must be connected to the ESP32 GND

Also of note, the above PPS, TX, and RX pin selections were changed in version 2.4 for better forward and backward compatibility between revisions of the ESP32-P4 chip. However, if an earlier version of the software has been working fine for you then you may be able to use the old pin specifications if you want to avoid rewiring your project. Please see the ESP32TimeServerSettings.h file for more information.

Up time / Reset button → ESP32-P4-ETH (optional)

Button ESP32-P4-ETH pin
One terminal GND
The other terminal GPIO 3

WS2812 RGB LED (optional)

LCD pin ESP32-P4-ETH pin
GND GND
DI 470Ω resistor GPIO 4
5v V5 / VBUS

Important with the WS2812 a 470Ω resistor is require between the DI and GPIO 4 pin

KY-016 RGB LED (optional)

LCD pin ESP32-P4-ETH pin
GND GND
BLUE GPIO 4
GREEN GPIO 5
RED GPIO 6

LCD 2004 (HD44780 + PCF8574 I²C backpack) → ESP32-P4-ETH (optional)

LCD pin ESP32-P4-ETH pin
GND GND
VCC 3V3
SLC/SCL GPIO 7
SDA GPIO 8

Refer to the pin definitions in main/ESP32TimeServerSettings.h.


3D Printed Case

A downloadable 3D printable enclosure designed for use the WaveShare ESP32-P4-ETH (with or without the POE hat) + Sparkfun GPS boards is included in the 3D printable case/ folder. Both .stl (print-ready) and .f3z (Fusion 360 editable source) files are provided so you can tweak the design to suit your needs.

Note: the 3D printable enclosure files also includes the needed models for version 1 (used an Olimex ESP32-PoE-ISO Rev. B dev board).


Software

Build and development environment

To build and flash ESP32TimeServer you will need Espressif's ESP-IDF v6.1 or above. If you don't already have this software installed, just follow the install instructions directly below:

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html

which include these links to get it:

Installation of ESP-IDF and Tools on Windows

Installation of ESP-IDF and Tools on Linux

Installation of ESP-IDF and Tools on macOS

If you want to further develop the project, Visual Studio Code with the ESP-IDF extension is recommended. However, they are not needed to build and flash the project - the instructions for that are below.

Both Visual Studio Code (Community Edition) and the ESP-IDF extension are free to download and use. Here is where you can find more information about them and get your copies:

For Linux users:

A kind user of this project has shared more detailed environment setup, build and flash instructions specific to Linux (Debian 13) - these can be found here

Dependencies

The SparkFun u-blox GNSS Arduino Library v3 (v3.1.14) is included as a git submodule in 3rdparty/SparkFun_u-blox_GNSS_v3. The local component wrapper in components/SparkFun_u-blox_GNSS_v3 builds it from that checked-out submodule.

The remaining dependencies are managed automatically via the ESP-IDF Component Manager (declared in main/idf_component.yml):

  • esp-idf-lib/hd44780 — LCD driver
  • esp-idf-lib/pcf8574 — I²C LCD backpack driver
  • espressif/arduino-esp32 — Arduino compatibility layer for OTA and serial
  • espressif/mqtt — MQTT client used for optional reporting

Note: The ESP-IDF Component Manager resolves these dependencies dynamically at build time. A dependencies.lock file is generated locally on first build but is intentionally not committed because it is git-ignored.

Setup

Setup Step 1 - Download

Create a folder for this project, clone this repository into it, and update the SparkFun library within it. For example:

c:
mkdir c:\temp\ESP32TimeServerProject
cd \temp\ESP32TimeserverProject
git clone --recursive https://github.com/roblatour/ESP32TimeServer
cd ESP32TimeServer
git submodule update --init --recursive

Setup Step 2 - Configuration

All user-configurable settings — GPIO pins, GPS options, LCD options, button support, time zone, etc. — are centralized in:

main/ESP32TimeServerSettings.h

Edit this file to match your desired hardware setup before building.

Note: The settings file indicates whether certain features are enabled. These include support for an Uptime/Restart Button, a Liquid Crystal Display, MQTT reporting, and Over the Ethernet Updates. Please also note, that if a Liquid Crystal Display is not connected, LIQUID_CRYSTAL_DISPLAY_ENABLED must be 0 (disabled) or a critical runtime error will occur.

Setup Step 3 - Build

Open a Command Prompt, load the ESP-IDF 6.1 environment, and remove any existing generated configuration before building. The first build downloads the Component Manager dependencies into managed_components; this generated folder is not part of the repository.

Enter the commands below to setup the build environment and build the project:

call C:\esp\v6.1\esp-idf\export.bat
if exist sdkconfig del sdkconfig

You will need to know your ESP32-P4 chip's revision number to build the program. To determine it connect your ESP32-P4 development board to your computer via a USB cable and enter the following command:

esptool.py -p COMx flash-id

Note: Replace COMx with your actual serial port. For example: COM6

The output of the above includes chip type and revision number.

Next, use the command below matching your ESP32-P4's chip revision number to build the project:

  • For ESP32-P4 chips at revision 3.1 and above (including the WaveShare ESP32-P4-WIFI6-POE-ETH and newer WaveShare ESP32-P4-ETH development boards):

    idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;config/esp32p4_rev_v3_1.defaults" set-target esp32p4 build
  • For ESP32-P4 chips at revision 3.0:

    idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;config/esp32p4_rev_v3_0.defaults" set-target esp32p4 build
  • For older ESP32-P4 chips with revisions prior to version 3.0 (including older Waveshare ESP32-P4-ETH development boards):

    idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;config/esp32p4_rev_pre_v3.defaults" set-target esp32p4 build

Setup Step 4 - Flash

In the same Command Prompt where ESP-IDF 6.1 was loaded:

idf.py -p COMx flash monitor

Note: Replace COMx with your actual serial port. For example: COM6

Important: Do not use --force to flash an image to an earlier revision ESP32-P4.

Over The Ethernet (OTE) Updates

Following the initial flash, OTE updates can be performed if OTE_UPDATES_ENABLED was set to 1 (Enabled) for the initial build and flash.

A VS Code task "ESP-IDF: OTE Upload over Ethernet" is included in .vscode/tasks.json. It builds the firmware and deploys it to the device over Ethernet using espota.py, so no USB cable is needed after the first flash. Alternatively, use the terminal command in UsefulPowerShellCommands.md in the misc folder.


Setting up your Network / Systems to make use of the ESP32 Time Server

Please see Setup.md


Validating Your Time Server

Once running, and with your Network and System changes setup, you can validate accuracy at https://time.is.

You're also welcome to use this open source software (also developed by me) to stress test your time server:

https://github.com/roblatour/TimeServerStressTest


License

This project is released under the MIT License — see the LICENSE file for details.


Supporting This Project

To help support this project, or to just say thanks, you're welcome to 'buy me a coffee'.

buy me a coffee


Copyright © 2026 Rob Latour

About

ESP32 NTP Stratum1 Time Server

Topics

Resources

Stars

80 stars

Watchers

9 watching

Forks

Releases

Packages

Contributors

Languages