mirror of
https://github.com/cjfranko/NTP-Timeturner.git
synced 2025-11-08 18:32:02 +00:00
Compare commits
No commits in common. "2e8bc9ac5ee49ff41812c9881d254a104ee37df4" and "2d46fccfbe49a1be2146bbd0936c3600583e3a95" have entirely different histories.
2e8bc9ac5e
...
2d46fccfbe
4 changed files with 241 additions and 28 deletions
28
README.md
28
README.md
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
Hachi synchronises timecode-locked systems by decoding incoming LTC (Linear Time Code) and broadcasting it as NTP/PTP — with the dedication our namesake would insist upon.
|
Hachi synchronises timecode-locked systems by decoding incoming LTC (Linear Time Code) and broadcasting it as NTP/PTP — with the dedication our namesake would insist upon.
|
||||||
|
|
||||||
Created by Chris Frankland-Wright and Chaos Rogers
|
Created by Chris Frankland-Wright and John Rogers
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Hardware Requirements
|
## 📦 Hardware Requirements
|
||||||
|
|
||||||
- Raspberry Pi 5 2GB (Dev Platform) but should be supported by Pi v3 (or better)
|
- Raspberry Pi 5 (Dev Platform) but should be supported by Pi v3 (or better)
|
||||||
- Debian Bookworm (64-bit recommended)
|
- Debian Bookworm (64-bit recommended)
|
||||||
- Teensy 4.0 - https://thepihut.com/products/teensy-4-0-headers
|
- Teensy 4.0 - https://thepihut.com/products/teensy-4-0-headers
|
||||||
- Audio Adapter Board for Teensy 4.0 (Rev D) - https://thepihut.com/products/audio-adapter-board-for-teensy-4-0
|
- Audio Adapter Board for Teensy 4.0 (Rev D) - https://thepihut.com/products/audio-adapter-board-for-teensy-4-0
|
||||||
|
|
@ -32,7 +32,7 @@ Created by Chris Frankland-Wright and Chaos Rogers
|
||||||
|
|
||||||
## 🖥️ Web Interface & API
|
## 🖥️ Web Interface & API
|
||||||
|
|
||||||
When running as a background daemon, Hachi provides a web interface for monitoring and configuration.
|
When running as a background daemon, TimeTurner provides a web interface for monitoring and configuration.
|
||||||
|
|
||||||
- **Access**: The web UI is available at `http://<raspberry_pi_ip>:8080`.
|
- **Access**: The web UI is available at `http://<raspberry_pi_ip>:8080`.
|
||||||
- **Functionality**: You can view the real-time sync status, see logs, and change all configuration options directly from your browser.
|
- **Functionality**: You can view the real-time sync status, see logs, and change all configuration options directly from your browser.
|
||||||
|
|
@ -50,7 +50,7 @@ When running as a background daemon, Hachi provides a web interface for monitori
|
||||||
|
|
||||||
## 🚀 Installation
|
## 🚀 Installation
|
||||||
|
|
||||||
The `setup.sh` script compiles and installs the Hachi application. You can run it by cloning the repository with `git` or by using the `curl` command below for a git-free installation.
|
The `setup.sh` script compiles and installs the TimeTurner application. You can run it by cloning the repository with `git` or by using the `curl` command below for a git-free installation.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
|
|
@ -86,27 +86,11 @@ The installation script automates the following steps:
|
||||||
|
|
||||||
After installation is complete, the script will provide instructions to start the service manually or to run the application in its interactive terminal mode.
|
After installation is complete, the script will provide instructions to start the service manually or to run the application in its interactive terminal mode.
|
||||||
|
|
||||||
```bash
|
|
||||||
The working directory is /opt/timeturner.
|
|
||||||
Default 'config.yml' installed to /opt/timeturner.
|
|
||||||
|
|
||||||
To start the service, run:
|
|
||||||
sudo systemctl start timeturner.service
|
|
||||||
|
|
||||||
To view live logs, run:
|
|
||||||
journalctl -u timeturner.service -f
|
|
||||||
|
|
||||||
To run the interactive TUI instead, simply run from the project directory:
|
|
||||||
cargo run
|
|
||||||
Or from anywhere after installation:
|
|
||||||
timeturner
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔄 Updating
|
## 🔄 Updating
|
||||||
|
|
||||||
If you installed Hachi by cloning the repository with `git`, you can use the `update.sh` script to easily update to the latest version.
|
If you installed TimeTurner by cloning the repository with `git`, you can use the `update.sh` script to easily update to the latest version.
|
||||||
|
|
||||||
**Note**: This script will not work if you used the `curl` one-line command for installation, as that method does not create a Git repository.
|
**Note**: This script will not work if you used the `curl` one-line command for installation, as that method does not create a Git repository.
|
||||||
|
|
||||||
|
|
@ -129,7 +113,7 @@ chronyc tracking | NTP Tracking
|
||||||
sudo nano /etc/chrony/chrony.conf | Default Chrony Conf File
|
sudo nano /etc/chrony/chrony.conf | Default Chrony Conf File
|
||||||
|
|
||||||
Add to top:
|
Add to top:
|
||||||
# Serve the system clock as a reference at stratum 1
|
# Serve the system clock as a reference at stratum 10
|
||||||
server 127.127.1.0
|
server 127.127.1.0
|
||||||
allow 127.0.0.0/8
|
allow 127.0.0.0/8
|
||||||
local stratum 1
|
local stratum 1
|
||||||
|
|
|
||||||
233
setup.sh
233
setup.sh
|
|
@ -97,7 +97,7 @@ echo "Common build dependencies installed."
|
||||||
# --- Install Python dependencies for testing ---
|
# --- Install Python dependencies for testing ---
|
||||||
echo "🐍 Installing Python dependencies for test scripts..."
|
echo "🐍 Installing Python dependencies for test scripts..."
|
||||||
if [ "$PKG_MANAGER" == "apt" ]; then
|
if [ "$PKG_MANAGER" == "apt" ]; then
|
||||||
# We no longer need hotspot dependencies
|
# python3-serial is the name for pyserial in apt
|
||||||
sudo apt install -y python3 python3-pip python3-serial
|
sudo apt install -y python3 python3-pip python3-serial
|
||||||
elif [ "$PKG_MANAGER" == "dnf" ]; then
|
elif [ "$PKG_MANAGER" == "dnf" ]; then
|
||||||
# python3-pyserial is the name for pyserial in dnf
|
# python3-pyserial is the name for pyserial in dnf
|
||||||
|
|
@ -217,8 +217,237 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# --- The entire WiFi hotspot and captive portal section has been removed ---
|
# --- Install and configure WiFi hotspot and captive portal ---
|
||||||
|
echo "📡 Installing and configuring WiFi hotspot and captive portal..."
|
||||||
|
|
||||||
|
if [ "$PKG_MANAGER" == "apt" ]; then
|
||||||
|
# Stop the service if it's running from a previous installation to prevent "Text file busy" error.
|
||||||
|
echo "Stopping existing nodogsplash service before installation..."
|
||||||
|
sudo systemctl stop nodogsplash || true
|
||||||
|
|
||||||
|
# We will use dnsmasq for DHCP, as the compiled nodogsplash version may not support the internal DHCP server.
|
||||||
|
# sudo apt-get remove --purge -y dnsmasq || true # This line is no longer needed.
|
||||||
|
|
||||||
|
# Install dependencies for hotspot and for building nodogsplash.
|
||||||
|
# ifupdown is needed to manage /etc/network/interfaces
|
||||||
|
sudo apt install -y hostapd dnsmasq git libmicrohttpd-dev libjson-c-dev iptables ifupdown
|
||||||
|
|
||||||
|
# Force iptables-legacy for nodogsplash
|
||||||
|
echo "Setting iptables-legacy mode for nodogsplash..."
|
||||||
|
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
|
||||||
|
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
||||||
|
|
||||||
|
echo "Building and installing nodogsplash from source..."
|
||||||
|
# Create a temporary directory for the build
|
||||||
|
BUILD_DIR=$(mktemp -d)
|
||||||
|
git clone https://github.com/nodogsplash/nodogsplash.git "$BUILD_DIR"
|
||||||
|
|
||||||
|
# Run the build in a subshell to isolate the directory change
|
||||||
|
(
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
# Manually install the systemd service file as 'make install' might not do it.
|
||||||
|
# This makes the script more robust.
|
||||||
|
if [ -f "debian/nodogsplash.service" ]; then
|
||||||
|
echo "Manually installing systemd service file..."
|
||||||
|
sudo cp debian/nodogsplash.service /etc/systemd/system/nodogsplash.service
|
||||||
|
# Reload systemd to recognize the new service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
else
|
||||||
|
echo "⚠️ Warning: nodogsplash.service file not found in source. Cannot set up as a service."
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up the build directory
|
||||||
|
sudo rm -rf "$BUILD_DIR"
|
||||||
|
echo "✅ nodogsplash installed successfully."
|
||||||
|
|
||||||
|
# Disable the standalone hostapd service to let NetworkManager manage it.
|
||||||
|
# We are now using the classic hostapd service, so unmask it.
|
||||||
|
sudo systemctl unmask hostapd
|
||||||
|
sudo systemctl enable hostapd
|
||||||
|
sudo systemctl enable nodogsplash
|
||||||
|
else
|
||||||
|
echo "This script is designed for Debian-based systems like Raspberry Pi OS."
|
||||||
|
echo "Skipping WiFi hotspot setup."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop services to configure
|
||||||
|
# Ensure services exist before trying to stop them
|
||||||
|
sudo systemctl stop hostapd || true
|
||||||
|
sudo systemctl stop dnsmasq || true
|
||||||
|
|
||||||
|
# --- Configure networking for AP mode ---
|
||||||
|
|
||||||
|
# Set the WiFi country code to prevent radio issues. This is a critical step.
|
||||||
|
echo "Setting WiFi Country Code to US..."
|
||||||
|
sudo raspi-config nonint do_wifi_country US
|
||||||
|
|
||||||
|
# Tell NetworkManager to ignore wlan0 completely to prevent conflicts.
|
||||||
|
echo "Configuring NetworkManager to ignore wlan0..."
|
||||||
|
sudo tee /etc/NetworkManager/conf.d/99-unmanaged-wlan0.conf > /dev/null <<EOF
|
||||||
|
[keyfile]
|
||||||
|
unmanaged-devices=interface-name:wlan0
|
||||||
|
EOF
|
||||||
|
# Also remove the DNS disabling config as it's no longer relevant for this method
|
||||||
|
sudo rm -f /etc/NetworkManager/conf.d/99-disable-dns.conf
|
||||||
|
sudo systemctl reload NetworkManager
|
||||||
|
|
||||||
|
# --- Configure networking for AP mode (using /etc/network/interfaces) ---
|
||||||
|
|
||||||
|
# 1. Uninstall dhcpcd5 to prevent any conflicts.
|
||||||
|
echo "Removing dhcpcd5 to switch to /etc/network/interfaces..."
|
||||||
|
sudo apt-get remove --purge -y dhcpcd5 || true
|
||||||
|
sudo systemctl disable dhcpcd || true
|
||||||
|
|
||||||
|
# 2. Configure a static IP for wlan0 directly in the interfaces file.
|
||||||
|
echo "Configuring static IP for wlan0 via /etc/network/interfaces..."
|
||||||
|
sudo tee /etc/network/interfaces > /dev/null <<EOF
|
||||||
|
# This file describes the network interfaces available on your system
|
||||||
|
# and how to activate them. For more information, see interfaces(5).
|
||||||
|
|
||||||
|
source /etc/network/interfaces.d/*
|
||||||
|
|
||||||
|
# The loopback network interface
|
||||||
|
auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
# The primary network interface (Ethernet) - managed by NetworkManager
|
||||||
|
allow-hotplug eth0
|
||||||
|
iface eth0 inet dhcp
|
||||||
|
|
||||||
|
# Static IP configuration for Fetch-Hachi AP
|
||||||
|
allow-hotplug wlan0
|
||||||
|
iface wlan0 inet static
|
||||||
|
address 10.0.252.1
|
||||||
|
netmask 255.255.255.0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Configure hostapd for the Access Point
|
||||||
|
echo "Configuring hostapd..."
|
||||||
|
sudo tee /etc/hostapd/hostapd.conf > /dev/null <<EOF
|
||||||
|
interface=wlan0
|
||||||
|
driver=nl80211
|
||||||
|
ssid=Fetch-Hachi
|
||||||
|
hw_mode=g
|
||||||
|
channel=7
|
||||||
|
ieee80211n=1
|
||||||
|
wmm_enabled=1
|
||||||
|
macaddr_acl=0
|
||||||
|
auth_algs=1
|
||||||
|
ignore_broadcast_ssid=0
|
||||||
|
EOF
|
||||||
|
# Point the hostapd service to the new config file.
|
||||||
|
sudo sed -i 's|#DAEMON_CONF=""|DAEMON_CONF="/etc/hostapd/hostapd.conf"|' /etc/default/hostapd
|
||||||
|
|
||||||
|
# Configure dnsmasq for DHCP
|
||||||
|
echo "Configuring dnsmasq..."
|
||||||
|
sudo tee /etc/dnsmasq.conf > /dev/null <<EOF
|
||||||
|
# Listen only on this interface
|
||||||
|
interface=wlan0
|
||||||
|
# Don't bind to all interfaces, only the one specified above
|
||||||
|
bind-interfaces
|
||||||
|
# Set the IP range for DHCP clients
|
||||||
|
dhcp-range=10.0.252.10,10.0.252.50,255.255.255.0,24h
|
||||||
|
# Provide a gateway address
|
||||||
|
dhcp-option=option:router,10.0.252.1
|
||||||
|
# Provide a DNS server address
|
||||||
|
dhcp-option=option:dns-server,10.0.252.1
|
||||||
|
# For captive portal, resolve all DNS queries to the AP itself
|
||||||
|
address=/#/10.0.252.1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Configure nodogsplash for captive portal
|
||||||
|
echo "Configuring nodogsplash..."
|
||||||
|
sudo tee /etc/nodogsplash/nodogsplash.conf > /dev/null <<EOF
|
||||||
|
GatewayInterface wlan0
|
||||||
|
GatewayAddress 10.0.252.1
|
||||||
|
MaxClients 250
|
||||||
|
AuthIdleTimeout 480
|
||||||
|
FirewallRuleSet preauthenticated-users {
|
||||||
|
# Allow DHCP for clients to get an IP address
|
||||||
|
FirewallRule allow udp port 67
|
||||||
|
FirewallRule allow udp port 68
|
||||||
|
# Allow DNS for captive portal detection
|
||||||
|
FirewallRule allow tcp port 53
|
||||||
|
FirewallRule allow udp port 53
|
||||||
|
# Allow HTTP for the captive portal redirect
|
||||||
|
FirewallRule allow tcp port 80
|
||||||
|
}
|
||||||
|
RedirectURL http://10.0.252.1/static/index.html
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Restart services in the correct order and add delays to prevent race conditions
|
||||||
|
echo "Restarting services..."
|
||||||
|
|
||||||
|
# Stop and disable systemd-resolved to prevent any DNS/DHCP conflicts
|
||||||
|
echo "Disabling systemd-resolved to ensure dnsmasq has full control..."
|
||||||
|
sudo systemctl stop systemd-resolved || true
|
||||||
|
sudo systemctl disable systemd-resolved || true
|
||||||
|
|
||||||
|
# Bring up the wlan0 interface manually
|
||||||
|
echo "Bringing up wlan0 interface..."
|
||||||
|
sudo ifdown wlan0 || true
|
||||||
|
sudo ifup wlan0
|
||||||
|
|
||||||
|
# Restart hostapd to create the access point
|
||||||
|
sudo systemctl restart hostapd
|
||||||
|
|
||||||
|
# Wait for the interface to come up and get the IP address
|
||||||
|
echo "Waiting for wlan0 to be configured..."
|
||||||
|
IP_CHECK=""
|
||||||
|
# Loop for up to 30 seconds waiting for the IP
|
||||||
|
for i in {1..15}; do
|
||||||
|
# The '|| true' prevents the script from exiting if grep finds no match
|
||||||
|
IP_CHECK=$(ip -4 addr show wlan0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' || true)
|
||||||
|
if [ "$IP_CHECK" == "10.0.252.1" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "Still waiting for IP..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check for the IP address before starting nodogsplash
|
||||||
|
if [ "$IP_CHECK" == "10.0.252.1" ]; then
|
||||||
|
echo "✅ wlan0 configured with IP $IP_CHECK."
|
||||||
|
|
||||||
|
# Add a small delay to ensure the interface is fully ready for dnsmasq
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo "Attempting to start dnsmasq service..."
|
||||||
|
if ! sudo systemctl restart dnsmasq; then
|
||||||
|
echo "❌ dnsmasq service failed to start. Displaying logs..."
|
||||||
|
sleep 2
|
||||||
|
sudo journalctl -u dnsmasq.service --no-pager -n 50
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ dnsmasq service started successfully."
|
||||||
|
|
||||||
|
if command -v nodogsplash &> /dev/null; then
|
||||||
|
echo "Attempting to start nodogsplash service..."
|
||||||
|
if ! sudo systemctl restart nodogsplash; then
|
||||||
|
echo "❌ nodogsplash service failed to start. Displaying logs..."
|
||||||
|
# Give a moment for logs to be written
|
||||||
|
sleep 2
|
||||||
|
sudo journalctl -u nodogsplash.service --no-pager -n 50
|
||||||
|
echo ""
|
||||||
|
echo "To debug further, run nodogsplash in the foreground with this command:"
|
||||||
|
echo " sudo /usr/bin/nodogsplash -f -d 7"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ nodogsplash service started successfully."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ Error: wlan0 failed to get the static IP 10.0.252.1. Found: '$IP_CHECK'."
|
||||||
|
echo "Please check 'sudo systemctl status hostapd' and 'cat /etc/network/interfaces'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ WiFi hotspot and captive portal configured. SSID: Fetch-Hachi, IP: 10.0.252.1"
|
||||||
|
echo "Clients will be redirected to http://10.0.252.1/static/index.html"
|
||||||
|
|
||||||
# 1. Build the release binary
|
# 1. Build the release binary
|
||||||
echo "📦 Building release binary with Cargo..."
|
echo "📦 Building release binary with Cargo..."
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Fetch | Hachi</title>
|
<title>NTP TimeTurner</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -129,7 +129,7 @@
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<p>
|
<p>
|
||||||
Built by Chris Frankland-Wright and Chaos Rogers | Have Blue Broadcast Media |
|
Built by Chris Frankland-Wright and John Rogers | Have Blue Broadcast Media |
|
||||||
<a href="https://github.com/cjfranko/NTP-Timeturner" target="_blank" rel="noopener noreferrer">https://github.com/cjfranko/NTP-Timeturner</a>
|
<a href="https://github.com/cjfranko/NTP-Timeturner" target="_blank" rel="noopener noreferrer">https://github.com/cjfranko/NTP-Timeturner</a>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ cargo build --release
|
||||||
|
|
||||||
# 3. Stop the currently running service to release the file lock
|
# 3. Stop the currently running service to release the file lock
|
||||||
echo "🛑 Stopping TimeTurner service..."
|
echo "🛑 Stopping TimeTurner service..."
|
||||||
sudo systemctl stop timeturner.service || true
|
sudo systemctl stop timeturner.service
|
||||||
|
|
||||||
# 4. Copy the new binary to the installation directory
|
# 4. Copy the new binary to the installation directory
|
||||||
echo "🚀 Deploying new binary..."
|
echo "🚀 Deploying new binary..."
|
||||||
sudo cp target/release/ntp_timeturner /opt/timeturner/timeturner
|
sudo cp target/release/timeturner /opt/timeturner/timeturner
|
||||||
|
|
||||||
# 5. Restart the service with the new binary
|
# 5. Restart the service with the new binary
|
||||||
echo "✅ Restarting TimeTurner service..."
|
echo "✅ Restarting TimeTurner service..."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue