Compare commits

..

No commits in common. "2e8bc9ac5ee49ff41812c9881d254a104ee37df4" and "2d46fccfbe49a1be2146bbd0936c3600583e3a95" have entirely different histories.

4 changed files with 241 additions and 28 deletions

View file

@ -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 stratum1 # Serve the system clock as a reference at stratum10
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
View file

@ -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..."

View file

@ -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>

View file

@ -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..."