Compare commits

...

25 commits

Author SHA1 Message Date
Chris Frankland-Wright
ea55d087b5 change default yaml to not have timeturning
Some checks are pending
Build for Raspberry Pi / Build for aarch64 (push) Waiting to run
2025-08-30 22:52:42 +01:00
Chris Frankland-Wright
af6dbcc9a7 added in chrony settings 2025-08-30 22:42:32 +01:00
Chris Frankland-Wright
169c9b9aef allow update of nodogsplash 2025-08-30 22:32:03 +01:00
Chris Frankland-Wright
6221eea98c removed pip for install 2025-08-30 22:29:25 +01:00
Chris Frankland-Wright
ac035a8e0b fix tmp and install python 2025-08-30 22:27:28 +01:00
Chris Frankland-Wright
f2e2fa9c7f renambled dns thing 2025-08-30 22:22:02 +01:00
Chris Frankland-Wright
3c73a0487b fix nodog install issue 2025-08-30 22:19:30 +01:00
Chris Frankland-Wright
360e0751f2 ugh... 2025-08-30 22:16:04 +01:00
Chris Frankland-Wright
a764b4d4ad remove dnsmasq 2025-08-30 22:12:32 +01:00
Chris Frankland-Wright
63bd17b71e asdfghjk 2025-08-30 22:07:17 +01:00
Chris Frankland-Wright
7db595259f more network config 2025-08-30 22:05:09 +01:00
Chris Frankland-Wright
e19b50fe2b moved nodogsplash to nmtui 2025-08-30 22:01:11 +01:00
Chris Frankland-Wright
cc1335f1a9 blah 2025-08-30 21:56:44 +01:00
Chris Frankland-Wright
5ca32b6f36 premature exit issue 2025-08-30 21:54:17 +01:00
Chris Frankland-Wright
1caa09ac46 added delay in process 2025-08-30 21:51:03 +01:00
Chris Frankland-Wright
57de9a98a5 updated to network-manager 2025-08-30 21:46:38 +01:00
Chris Frankland-Wright
0e7b583829 fix bug with service creation 2025-08-30 21:43:00 +01:00
Chris Frankland-Wright
e4c59b412b install json handler 2025-08-30 21:40:15 +01:00
Chris Frankland-Wright
dad5c2d06a update to pull nodogsplash and configure 2025-08-30 21:37:25 +01:00
Chris Frankland-Wright
baf674edd8 updated version of dogsplash 2025-08-30 21:20:26 +01:00
Chris Frankland-Wright
762f872e7c updated to pull directly 2025-08-30 21:17:39 +01:00
Chris Frankland-Wright
5eb706601f updated for nodogsplash 2025-08-30 21:14:09 +01:00
Chris Frankland-Wright
7773e62402 Merge branch 'main' of https://github.com/cjfranko/NTP-Timeturner 2025-08-30 21:08:26 +01:00
Chris Frankland-Wright
24c09fa233 updated setup.sh file 2025-08-30 21:07:48 +01:00
Chris Frankland-Wright
3f99488ea0 include yaml 2025-08-26 12:09:53 +01:00
3 changed files with 227 additions and 70 deletions

View file

@ -50,36 +50,37 @@ When running as a background daemon, TimeTurner provides a web interface for mon
## 🚀 Installation
The `setup.sh` script is provided to compile and install the TimeTurner application and its systemd service on a Debian-based system like Raspberry Pi OS.
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
- **Rust and Cargo**: The script requires the Rust programming language toolchain. If you don't have it, install it from [rustup.rs](https://rustup.rs/).
- **Internet Connection**: To download dependencies.
- **Curl and Unzip**: The script requires `curl` to download files and `unzip` for the git-free method. The setup script will attempt to install these if they are missing.
### Running the Installer
### Running the Installer (Recommended)
1. First, clone the repository:
```bash
git clone https://github.com/cjfranko/NTP-Timeturner.git
cd NTP-Timeturner
```
2. Make the script executable and run it. The script will use `sudo` for commands that require root privileges, so it may ask for your password.
```bash
chmod +x setup.sh
./setup.sh
```
This command downloads the latest version, unpacks it, and runs the setup script. Paste it into your Raspberry Pi terminal:
```bash
curl -L https://github.com/cjfranko/NTP-Timeturner/archive/refs/heads/main.zip -o NTP-Timeturner.zip && \
unzip NTP-Timeturner.zip && \
cd NTP-Timeturner-main && \
chmod +x setup.sh && \
./setup.sh
```
### What the Script Does
The installation script automates the following steps:
1. **Compiles the Binary**: Runs `cargo build --release` to create an optimised executable.
2. **Creates Directories**: Creates `/opt/timeturner` to store the application files.
3. **Installs Files**:
1. **Installs Dependencies**: Installs `git`, `curl`, `unzip`, and necessary build tools.
2. **Compiles the Binary**: Runs `cargo build --release` to create an optimised executable.
3. **Creates Directories**: Creates `/opt/timeturner` to store the application files.
4. **Installs Files**:
- The compiled binary is copied to `/opt/timeturner/timeturner`.
- The web interface assets from the `static/` directory are copied to `/opt/timeturner/static`.
- A symbolic link is created from `/usr/local/bin/timeturner` to the binary, allowing it to be run from any location.
4. **Sets up Systemd Service**:
5. **Sets up Systemd Service**:
- Copies the `timeturner.service` file to `/etc/systemd/system/`.
- Enables the service to start automatically on system boot.

View file

@ -12,8 +12,8 @@ defaultNudgeMs: 2
# Time-turning offsets. All values are added to the incoming LTC time.
# These can be positive or negative.
timeturnerOffset:
hours: 1
minutes: 2
seconds: 3
frames: 4
milliseconds: 5
hours: 0
minutes: 0
seconds: 0
frames: 0
milliseconds: 0

252
setup.sh
View file

@ -21,7 +21,8 @@ echo "Detected package manager: $PKG_MANAGER"
# --- Update System Packages ---
echo "Updating system packages..."
if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt update && sudo apt upgrade -y
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y -o Dpkg::Options::="--force-confold"
elif [ "$PKG_MANAGER" == "dnf" ]; then
sudo dnf upgrade -y
elif [ "$PKG_MANAGER" == "pacman" ]; then
@ -48,14 +49,29 @@ fi
echo "Installing common build dependencies..."
if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt update
sudo apt install -y build-essential libudev-dev pkg-config curl
sudo apt install -y build-essential libudev-dev pkg-config curl wget
elif [ "$PKG_MANAGER" == "dnf" ]; then
sudo dnf install -y gcc make perl-devel libudev-devel pkg-config curl
sudo dnf install -y gcc make perl-devel libudev-devel pkg-config curl wget
elif [ "$PKG_MANAGER" == "pacman" ]; then
sudo pacman -Sy --noconfirm base-devel libudev pkg-config curl
fi
echo "Common build dependencies installed."
# --- Install Python dependencies for testing ---
echo "🐍 Installing Python dependencies for test scripts..."
if [ "$PKG_MANAGER" == "apt" ]; then
# python3-serial is the name for pyserial in apt
sudo apt install -y python3 python3-pip python3-serial
elif [ "$PKG_MANAGER" == "dnf" ]; then
# python3-pyserial is the name for pyserial in dnf
sudo dnf install -y python3 python3-pip python3-pyserial
elif [ "$PKG_MANAGER" == "pacman" ]; then
# python-pyserial is the name for pyserial in pacman
sudo pacman -Sy --noconfirm python python-pip python-pyserial
fi
# sudo pip3 install pyserial # This is replaced by the native package manager installs above
echo "✅ Python dependencies installed."
# --- Apply custom splash screen ---
if [[ "$(uname)" == "Linux" ]]; then
echo "🖼️ Applying custom splash screen..."
@ -100,10 +116,10 @@ echo "Removing NTPD (if installed) and installing Chrony, NMTUI, Adjtimex..."
if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt update
sudo apt remove -y ntp || true # Remove ntp if it exists, ignore if not
sudo apt install -y chrony nmtui adjtimex
sudo apt install -y chrony network-manager adjtimex
sudo systemctl enable chrony --now
elif [ "$PKG_MANAGER" == "dnf" ]; then
sudo dnf remove -y ntp || true
sudo dnf remove -y ntp
sudo dnf install -y chrony NetworkManager-tui adjtimex
sudo systemctl enable chronyd --now
elif [ "$PKG_MANAGER" == "pacman" ]; then
@ -116,29 +132,142 @@ fi
echo "NTPD removed (if present). Chrony, NMTUI, and Adjtimex installed and configured."
# --- Configure Chrony to act as a local NTP server ---
echo "⚙️ Configuring Chrony to serve local time..."
# The path to chrony.conf can vary
if [ -f /etc/chrony/chrony.conf ]; then
CHRONY_CONF="/etc/chrony/chrony.conf"
elif [ -f /etc/chrony.conf ]; then
CHRONY_CONF="/etc/chrony.conf"
else
CHRONY_CONF=""
fi
if [ -n "$CHRONY_CONF" ]; then
# Comment out any existing pool, server, or sourcedir lines to prevent syncing with external sources
echo "Disabling external NTP sources..."
sudo sed -i -E 's/^(pool|server|sourcedir)/#&/' "$CHRONY_CONF"
# Add settings to the top of the file to serve local clock
# Using a temp file to prepend is safer than multiple sed calls
TEMP_CONF=$(mktemp)
cat <<EOF > "$TEMP_CONF"
# Serve the system clock as a reference at stratum 1
server 127.127.1.0
allow 127.0.0.0/8
local stratum 1
EOF
# Append the rest of the original config file after our new lines
cat "$CHRONY_CONF" >> "$TEMP_CONF"
sudo mv "$TEMP_CONF" "$CHRONY_CONF"
# Add settings to the bottom of the file to allow LAN clients
echo "Allowing LAN clients..."
sudo tee -a "$CHRONY_CONF" > /dev/null <<EOF
# Allow LAN clients to connect
allow 0.0.0.0/0
EOF
# Restart chrony to apply changes (service name can be chrony or chronyd)
echo "Restarting Chrony service..."
sudo systemctl restart chrony || sudo systemctl restart chronyd
echo "✅ Chrony configured."
else
echo "⚠️ Warning: chrony.conf not found. Skipping Chrony configuration."
fi
# --- Install and configure WiFi hotspot and captive portal ---
echo "📡 Installing and configuring WiFi hotspot and captive portal..."
if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt install -y hostapd dnsmasq nodogsplash
sudo systemctl unmask hostapd
sudo systemctl enable hostapd
# 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.
sudo apt install -y hostapd dnsmasq git libmicrohttpd-dev libjson-c-dev iptables
# 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.
sudo systemctl disable hostapd
sudo systemctl mask 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
sudo systemctl stop hostapd
sudo systemctl stop dnsmasq
sudo systemctl stop nodogsplash
# Ensure services exist before trying to stop them
sudo systemctl stop hostapd || true
sudo systemctl stop dnsmasq || true
# Configure static IP for wlan0
echo "Configuring static IP for wlan0..."
sudo sed -i '/^interface wlan0/d' /etc/dhcpcd.conf
sudo tee -a /etc/dhcpcd.conf > /dev/null <<EOF
interface wlan0
static ip_address=10.0.252.1/24
nohook wpa_supplicant
EOF
# Ensure NetworkManager is managing wlan0 by removing any conflicting configurations.
# This is the critical fix for the "No suitable device" error.
echo "Ensuring NetworkManager is managing wlan0..."
sudo rm -f /etc/NetworkManager/conf.d/99-unmanaged-wlan0.conf
sudo systemctl reload NetworkManager
# Configure static IP for wlan0 using NetworkManager (nmcli)
echo "Configuring static IP for wlan0 using NetworkManager..."
# Define the connection name
CON_NAME="TimeTurner-AP"
# If a connection with this name already exists, delete it to ensure a clean slate.
if nmcli c show --active | grep -q "$CON_NAME"; then
sudo nmcli c down "$CON_NAME" || true
fi
if nmcli c show | grep -q "$CON_NAME"; then
echo "Deleting existing '$CON_NAME' connection profile..."
sudo nmcli c delete "$CON_NAME" || true
fi
# Create a new connection profile for the Access Point with a static IP.
echo "Creating new '$CON_NAME' connection profile..."
sudo nmcli c add type wifi ifname wlan0 con-name "$CON_NAME" autoconnect yes ssid "TimeTurner"
sudo nmcli c modify "$CON_NAME" 802-11-wireless.mode ap 802-11-wireless.band bg
sudo nmcli c modify "$CON_NAME" 802-11-wireless-security.key-mgmt wpa-psk
sudo nmcli c modify "$CON_NAME" 802-11-wireless-security.psk "harry-ron-hermione"
sudo nmcli c modify "$CON_NAME" ipv4.method manual ipv4.addresses 10.0.252.1/24
# Configure dnsmasq for DHCP
echo "Configuring dnsmasq..."
@ -148,44 +277,64 @@ dhcp-range=10.0.252.10,10.0.252.50,255.255.255.0,24h
address=/#/10.0.252.1
EOF
# Configure hostapd
echo "Configuring hostapd..."
sudo tee /etc/hostapd/hostapd.conf > /dev/null <<EOF
interface=wlan0
driver=nl80211
ssid=TimeTurner
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=harry-ron-hermione
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
EOF
sudo sed -i 's|#DAEMON_CONF=""|DAEMON_CONF="/etc/hostapd/hostapd.conf"|' /etc/default/hostapd
# 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 50
ClientIdleTimeout 3600
MaxClients 250
AuthIdleTimeout 480
FirewallRuleSet preauthenticated-users {
FirewallRule allow tcp port 80
FirewallRule allow tcp port 53
FirewallRule allow udp port 53
}
RedirectURL http://10.0.252.1/static/index.html
EOF
# Restart services
sudo systemctl restart dhcpcd
sudo systemctl restart dnsmasq
sudo systemctl restart hostapd
sudo systemctl restart nodogsplash
# Restart services in the correct order and add delays to prevent race conditions
echo "Restarting services..."
# Bring up the new AP connection using nmcli
sudo nmcli c up "$CON_NAME"
# 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."
sudo systemctl restart dnsmasq
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 nmcli c show \"$CON_NAME\"' and 'ip addr show wlan0'."
exit 1
fi
echo "✅ WiFi hotspot and captive portal configured. SSID: TimeTurner, IP: 10.0.252.1"
echo "Clients will be redirected to http://10.0.252.1/static/index.html"
@ -212,6 +361,7 @@ sudo ln -sf $INSTALL_DIR/timeturner $BIN_DIR/timeturner
echo "✅ Binary and assets installed to $INSTALL_DIR, and binary linked to $BIN_DIR."
# 4. Install systemd service file
# Only needed for Linux systems (e.g., Raspberry Pi OS)
if [[ "$(uname)" == "Linux" ]]; then
echo "⚙️ Installing systemd service for Linux..."
sudo cp timeturner.service /etc/systemd/system/
@ -226,14 +376,20 @@ echo ""
echo "--- Setup Complete ---"
echo "The TimeTurner daemon is now installed."
echo "The working directory is $INSTALL_DIR."
echo "A default 'config.yml' will be created there on first run."
# Copy default config.yml from repo if it exists
if [ -f config.yml ]; then
sudo cp config.yml $INSTALL_DIR/
echo "Default 'config.yml' installed to $INSTALL_DIR."
else
echo "⚠️ No default 'config.yml' found in repository. Please add one if needed."
fi
echo ""
if [[ "$(uname)" == "Linux" ]]; then
echo "To start the service, run:"
echo " sudo systemctl start timeturner.service"
echo ""
echo "To view live logs, run:"
echo " journalctl -u timeturner.service -f"
echo " journalctl -u tim_turner.service -f"
echo ""
fi
echo "To run the interactive TUI instead, simply run from the project directory:"