This tool monitors serial output from a Meshtastic device to track which nodes are sending time information to the mesh network and identifies nodes with incorrect time settings.
Meshtastic uses a time quality hierarchy to determine which time sources to trust:
- RTCQualityGPS (Highest) - Time from GPS satellites
- RTCQualityNTP - Time from NTP server or phone app
- RTCQualityFromNet - Time from other mesh nodes
- RTCQualityDevice - Hardware RTC only
- RTCQualityNone (Lowest) - No time set
- Time is transmitted primarily through Position messages with a
timefield (seconds since Unix epoch) - Only nodes with quality time (RTCQualityNTP or RTCQualityGPS) include time in position broadcasts
- Time is only transmitted on PRIMARY channels
- Nodes without good time sources accept time from mesh (RTCQualityFromNet)
message Position {
fixed32 time = 4; // seconds since 1970 - used to set local RTC
fixed32 timestamp = 7; // GPS solution timestamp
int32 timestamp_millis_adjust = 8; // milliseconds adjustment
}- src/gps/RTC.cpp/h - Central time management
- src/modules/PositionModule.cpp - Sends/receives position with time
- protobufs/meshtastic/mesh.proto - Position message definition
# Python 3.6 or higher
python3 --version
# Install pyserial
pip3 install pyserial# Make the script executable
chmod +x meshtastic_time_monitor.py# Linux/Mac
python3 meshtastic_time_monitor.py /dev/ttyUSB0
# Windows
python3 meshtastic_time_monitor.py COM3# Set custom baud rate
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --baud 115200
# Set time difference threshold (default: 30 seconds)
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --threshold 60
# Parse JSON formatted logs (for ENABLE_JSON_LOGGING builds)
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --json
# Change statistics interval (default: 60 seconds)
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --stats-interval 120# Monitor with 60-second threshold, JSON parsing, stats every 2 minutes
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --threshold 60 --json --stats-interval 120# List USB serial devices
ls /dev/ttyUSB*
ls /dev/ttyACM*
# Or use dmesg to see what was connected
dmesg | grep tty# List serial devices
ls /dev/cu.*
ls /dev/tty.usb*
# Common ESP32 devices
ls /dev/cu.SLAB_USBtoUART
ls /dev/cu.usbserial-*# List COM ports in PowerShell
[System.IO.Ports.SerialPort]::getportnames()
# Or check Device Manager -> Ports (COM & LPT)[+] Connected to /dev/ttyUSB0 at 115200 baud
[+] Monitoring for time synchronization issues (threshold: 30s)
[+] Press Ctrl+C to stop and show statistics
✓ OK Node 0x87654321: Reported: 2026-01-10 18:30:45 UTC, Diff: 2s
❌ INCORRECT Node 0x12345678: Reported: 2025-12-25 12:00:00 UTC, Diff: 15d 6h
└─ WARNING: Time difference exceeds threshold!
✓ OK Node 0xabcdef00: Reported: 2026-01-10 18:30:50 UTC, Diff: 5s
======================================================================
STATISTICS SUMMARY
======================================================================
Node: 0x87654321
Samples: 15
Average time diff: 3s
Max time diff: 8s
Last seen: 2026-01-10 18:35:22 UTC
Last reported time: 2026-01-10 18:35:20 UTC
Node: 0x12345678
Samples: 8
Average time diff: 15d 6h
Max time diff: 15d 7h
Last seen: 2026-01-10 18:35:15 UTC
Last reported time: 2025-12-25 12:05:30 UTC
======================================================================
======================================================================
FINAL STATISTICS
======================================================================
❌ NODES WITH INCORRECT TIME (2):
Node: 0x12345678
Samples: 23
Average diff: 15d 6h
Max diff: 15d 8h
Last reported: 2025-12-25 12:15:45 UTC
Node: 0xdeadbeef
Samples: 5
Average diff: 2h 15m
Max diff: 2h 30m
Last reported: 2026-01-10 16:05:12 UTC
✓ NODES WITH CORRECT TIME (3):
0x87654321: avg diff 3s, 45 samples
0xabcdef00: avg diff 5s, 32 samples
0x11223344: avg diff 2s, 18 samples
======================================================================
- ✓ OK - Node's time is within the threshold
- ❌ INCORRECT - Node's time differs by more than the threshold
- WARNING - Alert for nodes exceeding the threshold
Nodes are identified by their hex ID (e.g., 0x87654321). This is the node's unique identifier on the mesh network.
The time difference shows how far off the node's reported time is from your local system time:
2s- 2 seconds5m 30s- 5 minutes 30 seconds2h 15m- 2 hours 15 minutes15d 6h- 15 days 6 hours
-
Check serial port permissions:
# Linux sudo usermod -a -G dialout $USER # Log out and back in # Or use sudo (not recommended) sudo python3 meshtastic_time_monitor.py /dev/ttyUSB0
-
Verify correct port:
# Test connection pio device monitor -e <your_board>
-
Check baud rate:
- Default is 115200, but some devices use different rates
- Try
--baud 921600or--baud 57600
-
Enable position broadcasting:
- Use the Meshtastic app to configure position updates
- Ensure position module is enabled in device settings
-
Check log level:
- The device must have logging enabled
- Check that
LOG_INFOorLOG_DEBUGis active
-
Try JSON mode:
- If your firmware is built with
ENABLE_JSON_LOGGING, use--jsonflag - This provides more detailed packet information
- If your firmware is built with
# Linux - Add user to dialout group
sudo usermod -a -G dialout $USER
# macOS - No special permissions needed usually
# Windows - Run as Administrator or check device drivers-
Node with GPS:
- Should have time accurate to within 1-2 seconds
- Consistent small differences are normal due to GPS update intervals
-
Node with Phone/NTP:
- Should be accurate to within 5-10 seconds
- May drift between updates (every 12 hours)
-
Node receiving from Mesh:
- Accuracy depends on source node quality
- May accumulate error if receiving from poor quality source
-
Node with RTC only:
- May drift significantly over time (minutes to hours per day)
- Should eventually sync from mesh if receiving position messages
- Large constant offset (hours/days) - Node's RTC was set incorrectly or has bad time source
- Increasing drift - Node's RTC is failing or has poor quality crystal
- Random time jumps - Node is switching between conflicting time sources
# Connect to device
meshtastic --host /dev/ttyUSB0
# Set time from your computer
meshtastic --set-time
# Or set specific time
meshtastic --set-time 1704988800 # Unix timestampimport meshtastic
import meshtastic.serial_interface
import time
# Connect to device
interface = meshtastic.serial_interface.SerialInterface('/dev/ttyUSB0')
# Set current time
interface.sendAdminMessage(time.time())
# Close connection
interface.close()- Open Meshtastic app
- Connect to node
- Go to Settings → Radio Configuration
- Time will automatically sync from phone
To get more detailed logs, you can build firmware with JSON logging enabled:
# Edit platformio.ini for your environment
# Add to build_flags:
-DENABLE_JSON_LOGGING=1
# Rebuild
pio run -e <your_board>
# Flash
pio run -e <your_board> -t upload
# Run monitor with JSON flag
python3 meshtastic_time_monitor.py /dev/ttyUSB0 --jsonPosition messages use meshtastic_PortNum_POSITION_APP = 3
The time field in Position messages is:
- Type:
fixed32(4 bytes) - Format: Seconds since Unix epoch (January 1, 1970 00:00:00 UTC)
- Range: 0 to 4,294,967,295 (year 2106)
Every packet also has an rx_time field set by the receiving node:
- This is the local time when the packet was received
- Different from the position
timefield which is when the position was measured
Issues and improvements welcome! Key areas for enhancement:
- Add node name resolution from NodeDB
- Support for multiple serial ports simultaneously
- Web dashboard for monitoring
- Alert notifications (email, webhook)
- Historical data logging to database
This script is provided as-is for monitoring Meshtastic devices. Use at your own risk.