What the Raspberry Pi time-server guides get wrong on a Pi 4, with the measurements. The headline artifact is a four-line pps-gpio patch: PREEMPT_RT force-threads IRQ handlers, and pps-gpio takes its timestamp inside its handler, so the realtime kernel puts a scheduler between the electrical edge and the clock. IRQF_NO_THREAD takes RMS offset from 2468 ns to 199 ns. - kernel/ the patch - dashboard/ live status page (position hidden by default) - docs-site/ the write-up (Astro/Starlight, brass, no tutorial section)
53 lines
2.0 KiB
Makefile
53 lines
2.0 KiB
Makefile
# gpsntp-dashboard — deploy to the Pi.
|
|
#
|
|
# Everything site-specific lives in .env (copy .env.example). Nothing in this
|
|
# file names a host, a domain, or a certificate path.
|
|
-include .env
|
|
export
|
|
|
|
PI ?= deploy@gps-ntp.local
|
|
KEY ?= ~/.ssh/id_ed25519
|
|
APPDIR ?= /opt/gpsntp-dashboard
|
|
DOMAIN ?= clock.example.internal
|
|
|
|
SSH = ssh -i $(KEY) $(PI)
|
|
RSYNC = rsync -az -e "ssh -i $(KEY)"
|
|
|
|
# Where your Let's Encrypt live/ directory is on THIS machine, and where the
|
|
# cert should land on the Pi. Only needed if you front the dashboard with TLS.
|
|
CERT_SRC ?= $(HOME)/.certs/$(DOMAIN)
|
|
CERT_DST ?= /etc/caddy/certs/$(DOMAIN)
|
|
|
|
.PHONY: deploy logs restart status lint run caddy cert-sync
|
|
|
|
deploy:
|
|
$(RSYNC) --delete --exclude '.venv' --exclude '.git' --exclude '__pycache__' --exclude 'dist' ./ $(PI):/tmp/gpsntp-src/
|
|
$(SSH) 'sudo mkdir -p $(APPDIR) && sudo rsync -a --delete --exclude .venv /tmp/gpsntp-src/ $(APPDIR)/ && sudo APPDIR=$(APPDIR) bash $(APPDIR)/deploy/deploy.sh'
|
|
|
|
logs:
|
|
$(SSH) 'journalctl -u gpsntp-dashboard -n 60 -f'
|
|
|
|
restart:
|
|
$(SSH) 'sudo systemctl restart gpsntp-dashboard'
|
|
|
|
status:
|
|
$(SSH) 'systemctl status gpsntp-dashboard --no-pager; curl -s localhost:8080/healthz'
|
|
|
|
# Renders deploy/Caddyfile.tmpl with $(DOMAIN) and installs it.
|
|
caddy:
|
|
sed 's|{{DOMAIN}}|$(DOMAIN)|g' deploy/Caddyfile.tmpl > /tmp/Caddyfile.rendered
|
|
$(RSYNC) /tmp/Caddyfile.rendered $(PI):/tmp/Caddyfile
|
|
$(SSH) 'sudo cp /tmp/Caddyfile /etc/caddy/Caddyfile && sudo caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile && sudo systemctl reload caddy && echo reloaded'
|
|
|
|
# Push a renewed cert to the Pi. The Pi issues nothing itself — see
|
|
# deploy/Caddyfile.tmpl for why.
|
|
cert-sync:
|
|
$(RSYNC) -L $(CERT_SRC)/fullchain.pem $(CERT_SRC)/privkey.pem $(PI):/tmp/
|
|
$(SSH) 'sudo mv /tmp/fullchain.pem /tmp/privkey.pem $(CERT_DST)/ && sudo chown -R caddy:caddy /etc/caddy/certs && sudo chmod 600 $(CERT_DST)/privkey.pem && sudo systemctl reload caddy && echo "cert synced + caddy reloaded"'
|
|
|
|
lint:
|
|
uvx ruff check src/
|
|
|
|
run:
|
|
GPSD_HOST=$${GPSD_HOST:-gps-ntp.local} uv run gpsntp-dashboard
|