I built a Stratum-1 NTP server at home
My friend Jacques surprised me with a GPS module and I made a good use of it. The components I used are:
- a Raspberry PI 4 (you can definitely use a v3, and probably a v2 as well),
- a cheap ass GPS module (less than €5) from Ali,
- and an optional GPS antenna, stiched to my skylight window, to get a better reception.
I was following the awesome post of Austin’s Nerdy Things; however there were some differences (maybe coming from the newer Raspbian version?) that I’m going to explain in this post.
Step 0
I did exactly as described except there’s an extra step to do, which comes useful later in step 4.5: disabling the factory-default serial console that would block receiving the GPS data. For this you just need to run raspi-config:
sudo raspi-config
Select Interface Options, then Serial Port. The first question asks if you want a serial console, answer No to this. Then it asks if you want to enable serial port at all, answer Yes to this.
Step 1
I did everything the same way as described in the original post.
Step 2
Again the same as in the original post, except 5V pin is called VCC instead of VIN:
Step 3
A slight difference in the loaded modules, however this doesn’t affect the configurations you need to apply before and after this step:
adosztal@raspi4:~ $ lsmod | grep pps
pps_ldisc 16384 2
pps_gpio 16384 2
Running sudo ppstest /dev/pps0
gave similar results to Austin’s post:
adosztal@raspi4:~ $ sudo ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1650867765.999998081, sequence: 226856 - clear 0.000000000, sequence: 0
source 0 - assert 1650867766.999995683, sequence: 226857 - clear 0.000000000, sequence: 0
source 0 - assert 1650867768.000001360, sequence: 226858 - clear 0.000000000, sequence: 0
source 0 - assert 1650867768.999998352, sequence: 226859 - clear 0.000000000, sequence: 0
Step 4
In addition to setting the gpsd daemon’s devices and options to the values described in the post, enabling the service should be done using the proper systemd commands:
sudo systemctl enable gpsd.socket gpsd.socket
sudo systemctl enable gpsd.socket gpsd.service
sudo systemctl start gpsd.socket gpsd.socket
sudo systemctl start gpsd.socket gpsd.service
Note: There are some articles on the internet that suggest disabling gpsd.socket but those run the daemon in an ad-hoc fashion from the CLI. To get a reliable service, you need to enable these daemons.
Step 4.5
This is where I spent some time troubleshooting before I realized the serial console is locking my port. As I mentioned in step 3, running sudo ppstest /dev/pps0
gave proper results but when I ran gpsmon
, I just saw some JSON output without any valuable information. First I was afraid it was an unresolvable problem with the hardware until I finally figured out the root cause was the locked ttyS0 port; fixing that resolved the issue and gpsmon
shows a bunch of satellites:
tcp://localhost:2947 NMEA0183>
┌──────────────────────────────────────────────────────────────────────────────┐or":14}
│Time: 2022-04-25T06:40:01.000Z Lat: 47 11.584590' N Lon: 18 27.262610' E │r":"u-blox","subtype":"SW 1.00
└───────────────────────────────── Cooked TPV ─────────────────────────────────┘2022-04-25T06:38:57.386Z","fla
┌──────────────────────────────────────────────────────────────────────────────┐02},{"class":"DEVICE","path":"
│ GPGSV GPGLL GPRMC GPVTG GPGGA GPGSA │
└───────────────────────────────── Sentences ──────────────────────────────────┘false,"timing":false,"split24"
┌───────────────────────┌─────────────────────────┌────────────────────────────┐
│ SVID PRN Az El SN HU│Time: 064001.00 │Time: 064001.00 │
│GP 12 12 249 49 12 Y│Latitude: 4711.58459 N │Latitude: 4711.58459 │
│GP 17 17 56 38 16 Y│Longitude: 01827.26261 E │Longitude: 01827.26261 │
│GP 19 19 82 51 21 Y│Speed: 0.723 │Altitude: 162.6 │
│GP 24 24 300 76 23 Y│Course: 169.04 │Quality: 1 Sats: 04 │
│GP 1 1 17 3 16 N│Status: A FAA:A │HDOP: 3.77 │
│GP 6 6 112 8 16 N│MagVar: │Geoid: 39.7 │
│GP 10 10 294 11 3 N└───────── RMC ───────────└─────────── GGA ────────────┘
│GP 13 13 165 20 7 N┌─────────────────────────┌────────────────────────────┐
│GP 14 14 64 6 0 N│Mode: A3 Sats: 12 17 19 +│UTC: RMS: │
│GP 15 15 200 36 5 N│DOP H=3.77 V=4.49 P=5.86 │MAJ: MIN: │
│GP 23 23 263 7 0 N│TOFF: 0.135858576 │ORI: LAT: │
│GP 25 25 249 8 0 N│PPS: -0.000004742 │LON: ALT: │
└───v──── GSV ──────────└────── GSA + PPS ────────└─────────── GST ────────────┘
(66) $GPGSV,4,3,14,19,51,082,23,23,07,263,,24,76,300,25,25,08,249,*7E
(42) $GPGSV,4,4,14,28,29,060,25,32,05,326,*7F
(52) $GPGLL,4711.58523,N,01827.26245,E,064000.00,A,A*6A
------------------- PPS offset: -0.000004742 ------
(68) $GPRMC,064001.00,A,4711.58459,N,01827.26261,E,0.723,,250422,,,A*7D
(35) $GPVTG,,T,,M,0.723,N,1.339,K,A*2D
(75) $GPGGA,064001.00,4711.58459,N,01827.26261,E,1,04,3.77,162.6,M,39.7,M,,*5D
(50) $GPGSA,A,3,17,12,19,24,,,,,,,,,5.86,3.77,4.49*08
(70) $GPGSV,4,1,14,01,03,017,16,06,08,112,16,10,11,294,03,12,49,249,12*7E
(68) $GPGSV,4,2,14,13,20,165,07,14,06,064,,15,36,200,05,17,38,056,16*71
(66) $GPGSV,4,3,14,19,51,082,21,23,07,263,,24,76,300,23,25,08,249,*7A
(42) $GPGSV,4,4,14,28,29,060,24,32,05,326,*7E
(52) $GPGLL,4711.58459,N,01827.26261,E,064001.00,A,A*61
Final results
Once I fixed the issues, I saw my time server getting very reliable data (<200 ns offset):
adosztal@raspi4:~ $ chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#x NMEA 0 4 377 13 -75ms[ -75ms] +/- 1198us
#* PPS 0 4 377 11 +85ns[ +156ns] +/- 215ns
^- vps.poljakovi.cz 2 10 377 150 -2270us[-2269us] +/- 44ms
^- herbrand.noumicek.cz 2 10 377 227 -2368us[-2366us] +/- 39ms
^- host189-248-2-81.serverd> 2 10 377 272 -3426us[-3424us] +/- 15ms
^- ntp3.kashra-server.com 2 10 377 103 -1995us[-1995us] +/- 33ms
I still kept some NTP servers for two reasons:
- For failover if something breaks.
- For some reason PPS was marked as “in error” if I didn’t have any other sources.