Creare un Server NTP Stratum-1 con Raspberry Pi
Le basi
Partiamo dalle basi: Come fa il vostro elaboratore a sapere l'ora in questo preciso istante?
La risposta è NTP - Network Time Protocol. Un protocollo Client-Server che permette la sincronizzazione dell'ora degli elaboratori su una rete.
Il funzionamento in grandi linee è il seguente:
- I server NTP sono divisi in due macrocategorie:
- Primari, definiti Stratum-1. Sono collegati direttamente ad una precisa sorgente orario (Orologio Atomico, GNSS...)
- Secondari, definiti Stratum-[n] (n≥2). Questi si sincronizzano con un server Stratum-[k] (k≥1 , k=(n-1)) mediante TCP-IP.
- I client hanno a bordo un Software (definito Client NTP) che interroga il Server NTP definito localmente. Di seguito un esempio di Sistemi Operativi, relativo software e Server NTP predefinito.
Sistema Operativo Software Server Predefinito Microsoft Windows w32time time.windows.com Apple MacOS, iOS, iPadOS... sntp time.apple.com GNU/Linux ntpd dipende dalla distro - Quando il client interroga il server, un preciso calcolo matematico azzera (o meglio, tende ad azzerare il più possibile) il disturbo di tempo generato dalla latenza a causa della distanza fisica tra gli elaboratori. Provvede quindi ad aggiornare l'orario localmente.
Hardware
Utilizzeremo tre componenti principali per realizzare il nostro Server NTP:
- Raspberry Pi 4B
- Uputronics GPS/RTC Expansion Board (link)
- Antenna GPS Esterna (link). Da tenere presente che è necessario utilizzare un'antenna attiva (quindi con un amplificatore interno alimentato a 3-5V) per garantire una ricezione ottimale da parte della scheda GPS.
L'antenna dovrà essere posizionata con una perfetta visione del cielo per garantire una corretta ricezione del segnale GPS, maggiori info nella sezione successiva.
Software
Eseguiremo sul nostro Raspberry Pi una versione di Raspbian basata su Debian 11 Bullseye (in particolare la release 2024.03.12) senza GUI.
Poichè il nostro interesse principale è eseguire il Raspberry senza uso di periferiche esterne (monitor, tastiera, mouse...), lo configureremo in modalità Headless.
Una volta scritta la immagine del Sistema Operativo sulla scheda microSD, monteremo la partizione di boot ed apriremo un terminale sulla directory radice.
touch ssh
Creeremo successivamente una nostra utenza mediante il comando
echo nostronomeutente:$(echo "nostrapassword" | openssl passwd -6 -stdin) >> userconf.txt
Dopo aver smontato le partizioni ed espulso la scheda microSD, assembleremo il nostro Raspberry Pi e lo collegheremo alla rete.
Dopo fatto accesso mediante ssh iniziamo a configurare il Sistema Operativo:
- Aggiorniamo i pacchetti con
sudo apt-get update
- Installiamo i pacchetti necessari con
sudo apt-get install vim python3-smbus i2c-tools gpsd pps-tools chrony
- Lanciamo
raspi-config
ed abilitiamo l'interfaccia I2C. - Eseguiamo
sudo dpkg-reconfigure tzdata
e selezioniamo Europe/Rome - Opz. Rinominiamo l'hostname del nostro Raspberry Pi editando il file
/etc/hostname
- Editiamo il file
/boot/config.txt
aggiungendo le seguenti righe:dtoverlay=i2c-rtc,rv3028
(per caricare il driver i2c)dtoverlay=pi3-disable-bt
(per disabilitare il bluetooth)enable_uart=1
per abilitare la porta serialedtoverlay=pps-gpio,gpiopin=18
per definire il pin dove ricevere il segnale PPS [1].arm_64bit=0
- A causa di un bug nel Kernel Linux Custom dovremo forzare l'architettura ARM 32-bit [2].
- Disabilitiamo la Console Seriale via UART con i comandi:
sudo systemctl stop serial-getty@ttyAMA0.service
sudo systemctl disable serial-getty@ttyAMA0.service
- Rimuoviamo da
/boot/cmdline.txt
la stringaconsole=serial0,115200
- Aggiungiamo a
/boot/cmdline.txt
la stringabcm2708.pps_gpio_pin=18
Configuriamo ora GPSD, il software che ci permetterà di leggere in modo umano i dati ricevuti dalla Scheda GPS.
- Editiamo il file
/etc/default/gpsd
come di seguito:
DEVICES="/dev/ttyAMA0"
GPSD_OPTIONS="-n -G -s 115200"
USBAUTO="false"
cgps
visualizzeremo i dati ricevuti dalla scheda GPS. Dopo qualche minuto dall'avvio leggeremo (finalmente!) Status: 3D FIX (n secs). Ciò significa che abbiamo correttamente agganciato un minimo di 4 satelliti (Il numero esatto è indicato in alto a destra).Successivamente configureremo PPS (Pulse per-second) per ricevere un impulso al secondo assieme all'orario in formato Unix Time Stamp. Utilizzeremo PPS al posto dei dati forniti mediante porta seriale UART poichè quest'ultima genera troppa latenza e noi necessitiamo di precisione (!).
- Faremo caricare i driver PPS all'avvio del S.O. creando il file
/etc/modules-load.d/raspberrypi.conf
ed aggiungendoci le seguenti righe:
pps-gpio
pps-ldisc - Dopo un riavvio, lanciando il comando
dmesg | grep pps
dovremo poter leggere che il driver PPS è stato correttamente caricato, un segnale PPS valido è stato trovato e che è stato registrato. - Lanciando
ppstest /dev/pps0
riceveremo come output, una volta al secondo, la sorgente PPS contenente l'orario in formato Unix.
Configuriamo ora il Server vero e proprio, chrony.
- Creiamo delle regole udev ad-hoc per l'accesso alle porte pps0 e ttyAMA0 per chrony creando il file
/etc/udev/rules.d/pps-sources.rules
ed inserendoci le seguenti righe:
KERNEL=="pps0", OWNER="root", GROUP="_chrony", MODE="0660"
KERNEL=="ttyS0", RUN+="/bin/setserial -v /dev/%k low_latency irq 4" - Fermiamo il time server locale fornito da systemd con i seguenti comandi:
sudo systemctl stop systemd-timedated
sudo systemctl disable systemd-timedated - Editiamo il file
/etc/chrony/chrony.conf
con le seguenti righe:
refclock PPS /dev/pps0 lock GPS
refclock SHM 0 refid GPS precision 1e-1 offset 0.01 delay 0.2 noselect
allow 192.168/16
Conclusioni
Per vedere se tutto è andato a buon fine sarà sufficiente collegarsi con il proprio elaboratore alla stessa rete del Raspberry Pi e:
- Da Ambiente Microsoft Windows:
- Aprire Pannello di controllo
- Aprire Data e Ora
- Selezionare la tab Ora Internet quindi Cambia impostazioni
- Modificare time.windows.com con l'indirizzo IP del Raspberry Pi od il suo Hostname
- Premere su Sincronizza Ora
- Da Ambiente GNU/Linux:
- Installare il pacchetto ntpdate
- Lanciare il comando
ntpdate -q indirizzoIPoHostname
- Da Ambiente Android:
- Installare l'App NTPSync
- Impostare l'IP/Hostname del Raspberry Pi nella sezione Server NTP
- Toccare su Query/Query Dettagliata
Riferimenti
[1] - Datasheet Scheda Uputronics (Link 1) (Link 2)
[2] - Bug Kernel Linux Custom Raspberry Pi (Link)