A high-precision time synchronization library for ESP32 devices using the ESP-NOW protocol. Achieve microsecond-level synchronization between multiple ESP32 devices without requiring WiFi infrastructure.
- High Precision: Microsecond-level time synchronization
- No WiFi Required: Uses ESP-NOW for direct device communication
- Master-Client Architecture: One master provides time reference for multiple clients
- Automatic Peer Discovery: Master automatically registers connecting clients
- LED Synchronization: Built-in support for synchronized LED blinking
- Comprehensive Statistics: Detailed sync performance metrics
- Configurable Parameters: Customize sync intervals, timeouts, and smoothing
- Callback Support: Event-driven notifications for sync status changes
- Download or clone this library
- Place it in your Arduino libraries folder (
~/Arduino/libraries/ESPNowTimeSync/) - Restart Arduino IDE
- Include the library:
#include <ESPNowTimeSync.h>
#include <ESPNowTimeSync.h>
ESPNowTimeSync timeSync;
void setup() {
Serial.begin(115200);
timeSync.begin(true); // true = master
timeSync.startSync();
Serial.printf("Master MAC: %s\n", WiFi.macAddress().c_str());
}
void loop() {
delay(1000);
}#include <ESPNowTimeSync.h>
// Replace with your master's MAC address
const uint8_t MASTER_MAC[6] = {0xd8, 0x3b, 0xda, 0x42, 0xe6, 0x8c};
ESPNowTimeSync timeSync;
void setup() {
Serial.begin(115200);
timeSync.begin(false, MASTER_MAC); // false = client
timeSync.startSync();
}
void loop() {
timeSync.update(); // Important: call regularly for clients
delay(100);
}#include <ESPNowTimeSync.h>
#include <ESPNowTimeSyncLED.h>
ESPNowTimeSync timeSync;
ESPNowTimeSyncLED ledSync(timeSync, 2); // Pin 2
void setup() {
timeSync.begin(false, MASTER_MAC);
ledSync.begin();
timeSync.startSync();
ledSync.start();
}
void loop() {
timeSync.update();
delay(100);
}bool begin(bool is_master, const uint8_t* master_mac = nullptr)bool begin(bool is_master, const uint8_t* master_mac, const TimeSyncConfig& config)
void startSync()- Start synchronization processvoid stopSync()- Stop synchronizationvoid update()- Update sync (call regularly for clients)
int64_t getSyncedTime()- Get current synchronized time in microsecondsint64_t getOffset()- Get current time offset from masterbool isSynchronized()- Check if device is synchronized
SyncStats getStats()- Get detailed synchronization statisticsvoid resetStats()- Reset statistics counters
void onSyncStatus(SyncStatusCallback callback)- Sync status changesvoid onSyncEvent(SyncEventCallback callback)- Successful sync events
ESPNowTimeSyncLED(ESPNowTimeSync& timeSync, int ledPin = 2)void begin()- Initialize LED synchronization
void setPulseWidth(uint32_t pulse_us)- Set LED pulse durationvoid setInterval(uint32_t interval_us)- Set blink interval
void start()- Start LED synchronizationvoid stop()- Stop LED synchronizationbool isRunning()- Check if LED sync is active
TimeSyncConfig config;
config.channel = 0; // WiFi channel (0-13)
config.smoothing_alpha = 0.05f; // Offset smoothing (0.01-0.5)
config.sync_interval_ms = 1000; // Sync frequency
config.response_timeout_ms = 50; // Response timeout
config.enable_logging = true; // Debug output
config.log_interval_syncs = 10; // Log every N syncs
config.resync_interval_ms = 200; // Faster retry when unsynced
config.max_missed_responses = 3; // Mark unsynced after N timeouts
timeSync.begin(false, MASTER_MAC, config);- Typical Accuracy: ±10-50 microseconds between devices
- Sync Frequency: 1 Hz (configurable)
- Network Latency: <5ms typical ESP-NOW round-trip
- Startup Time: 3-5 seconds to achieve stable synchronization
-
Devices not syncing
- Verify master MAC address is correct
- Check WiFi channel compatibility
- Ensure devices are within ESP-NOW range (~200m)
-
Poor sync accuracy
- Reduce
sync_interval_msfor faster convergence - Adjust
smoothing_alpha(lower = more stable) - Check for WiFi interference
- Reduce
-
Frequent timeouts
- Increase
response_timeout_ms - Check device placement and interference
- Verify power supply stability
- If the master was offline and comes back, the client now retries faster when unsynced (
resync_interval_ms) and marks itself unsynchronized aftermax_missed_responsesconsecutive misses, enabling quick re-lock.
- Increase
-
Channel mismatch
- Set
config.channelto a fixed channel used by all devices. The library sets the radio channel whenchannel > 0, improving reliability after restarts.
- Set
Enable logging in configuration:
config.enable_logging = true;
config.log_interval_syncs = 5; // Log every 5 syncsSample output:
[TimeSync] Sync #50: offset=-23 µs, smoothed=-18.5 µs, RTT=1247 µs, success=98.0%, syncTime=1234567890 µs
The library includes several examples:
- BasicMaster: Simple master setup
- BasicClient: Simple client setup
- LEDSync: Synchronized LED blinking
- AdvancedConfig: Custom configuration and callbacks
This library is released under the MIT License. See LICENSE file for details.
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.