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 ## 🚀 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 ### 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: This command downloads the latest version, unpacks it, and runs the setup script. Paste it into your Raspberry Pi terminal:
```bash
git clone https://github.com/cjfranko/NTP-Timeturner.git ```bash
cd NTP-Timeturner curl -L https://github.com/cjfranko/NTP-Timeturner/archive/refs/heads/main.zip -o NTP-Timeturner.zip && \
``` unzip NTP-Timeturner.zip && \
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. cd NTP-Timeturner-main && \
```bash chmod +x setup.sh && \
chmod +x setup.sh ./setup.sh
./setup.sh ```
```
### What the Script Does ### What the Script Does
The installation script automates the following steps: The installation script automates the following steps:
1. **Compiles the Binary**: Runs `cargo build --release` to create an optimised executable. 1. **Installs Dependencies**: Installs `git`, `curl`, `unzip`, and necessary build tools.
2. **Creates Directories**: Creates `/opt/timeturner` to store the application files. 2. **Compiles the Binary**: Runs `cargo build --release` to create an optimised executable.
3. **Installs Files**: 3. **Creates Directories**: Creates `/opt/timeturner` to store the application files.
4. **Installs Files**:
- The compiled binary is copied to `/opt/timeturner/timeturner`. - The compiled binary is copied to `/opt/timeturner/timeturner`.
- The web interface assets from the `static/` directory are copied to `/opt/timeturner/static`. - 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. - 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/`. - Copies the `timeturner.service` file to `/etc/systemd/system/`.
- Enables the service to start automatically on system boot. - 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. # Time-turning offsets. All values are added to the incoming LTC time.
# These can be positive or negative. # These can be positive or negative.
timeturnerOffset: timeturnerOffset:
hours: 1 hours: 0
minutes: 2 minutes: 0
seconds: 3 seconds: 0
frames: 4 frames: 0
milliseconds: 5 milliseconds: 0

252
setup.sh
View file

@ -21,7 +21,8 @@ echo "Detected package manager: $PKG_MANAGER"
# --- Update System Packages --- # --- Update System Packages ---
echo "Updating system packages..." echo "Updating system packages..."
if [ "$PKG_MANAGER" == "apt" ]; then 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 elif [ "$PKG_MANAGER" == "dnf" ]; then
sudo dnf upgrade -y sudo dnf upgrade -y
elif [ "$PKG_MANAGER" == "pacman" ]; then elif [ "$PKG_MANAGER" == "pacman" ]; then
@ -48,14 +49,29 @@ fi
echo "Installing common build dependencies..." echo "Installing common build dependencies..."
if [ "$PKG_MANAGER" == "apt" ]; then if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt update 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 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 elif [ "$PKG_MANAGER" == "pacman" ]; then
sudo pacman -Sy --noconfirm base-devel libudev pkg-config curl sudo pacman -Sy --noconfirm base-devel libudev pkg-config curl
fi fi
echo "Common build dependencies installed." 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 --- # --- Apply custom splash screen ---
if [[ "$(uname)" == "Linux" ]]; then if [[ "$(uname)" == "Linux" ]]; then
echo "🖼️ Applying custom splash screen..." echo "🖼️ Applying custom splash screen..."
@ -100,10 +116,10 @@ echo "Removing NTPD (if installed) and installing Chrony, NMTUI, Adjtimex..."
if [ "$PKG_MANAGER" == "apt" ]; then if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt update sudo apt update
sudo apt remove -y ntp || true # Remove ntp if it exists, ignore if not 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 sudo systemctl enable chrony --now
elif [ "$PKG_MANAGER" == "dnf" ]; then 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 dnf install -y chrony NetworkManager-tui adjtimex
sudo systemctl enable chronyd --now sudo systemctl enable chronyd --now
elif [ "$PKG_MANAGER" == "pacman" ]; then elif [ "$PKG_MANAGER" == "pacman" ]; then
@ -116,29 +132,142 @@ fi
echo "NTPD removed (if present). Chrony, NMTUI, and Adjtimex installed and configured." 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 --- # --- Install and configure WiFi hotspot and captive portal ---
echo "📡 Installing and configuring WiFi hotspot and captive portal..." echo "📡 Installing and configuring WiFi hotspot and captive portal..."
if [ "$PKG_MANAGER" == "apt" ]; then if [ "$PKG_MANAGER" == "apt" ]; then
sudo apt install -y hostapd dnsmasq nodogsplash # Stop the service if it's running from a previous installation to prevent "Text file busy" error.
sudo systemctl unmask hostapd echo "Stopping existing nodogsplash service before installation..."
sudo systemctl enable hostapd 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 sudo systemctl enable nodogsplash
else
echo "This script is designed for Debian-based systems like Raspberry Pi OS."
echo "Skipping WiFi hotspot setup."
fi fi
# Stop services to configure # Stop services to configure
sudo systemctl stop hostapd # Ensure services exist before trying to stop them
sudo systemctl stop dnsmasq sudo systemctl stop hostapd || true
sudo systemctl stop nodogsplash sudo systemctl stop dnsmasq || true
# Configure static IP for wlan0 # Ensure NetworkManager is managing wlan0 by removing any conflicting configurations.
echo "Configuring static IP for wlan0..." # This is the critical fix for the "No suitable device" error.
sudo sed -i '/^interface wlan0/d' /etc/dhcpcd.conf echo "Ensuring NetworkManager is managing wlan0..."
sudo tee -a /etc/dhcpcd.conf > /dev/null <<EOF sudo rm -f /etc/NetworkManager/conf.d/99-unmanaged-wlan0.conf
interface wlan0 sudo systemctl reload NetworkManager
static ip_address=10.0.252.1/24
nohook wpa_supplicant # Configure static IP for wlan0 using NetworkManager (nmcli)
EOF 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 # Configure dnsmasq for DHCP
echo "Configuring dnsmasq..." 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 address=/#/10.0.252.1
EOF 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 # Configure nodogsplash for captive portal
echo "Configuring nodogsplash..." echo "Configuring nodogsplash..."
sudo tee /etc/nodogsplash/nodogsplash.conf > /dev/null <<EOF sudo tee /etc/nodogsplash/nodogsplash.conf > /dev/null <<EOF
GatewayInterface wlan0 GatewayInterface wlan0
GatewayAddress 10.0.252.1 GatewayAddress 10.0.252.1
MaxClients 50 MaxClients 250
ClientIdleTimeout 3600 AuthIdleTimeout 480
FirewallRuleSet preauthenticated-users { FirewallRuleSet preauthenticated-users {
FirewallRule allow tcp port 80 FirewallRule allow tcp port 80
FirewallRule allow tcp port 53
FirewallRule allow udp port 53
} }
RedirectURL http://10.0.252.1/static/index.html RedirectURL http://10.0.252.1/static/index.html
EOF EOF
# Restart services # Restart services in the correct order and add delays to prevent race conditions
sudo systemctl restart dhcpcd echo "Restarting services..."
sudo systemctl restart dnsmasq # Bring up the new AP connection using nmcli
sudo systemctl restart hostapd sudo nmcli c up "$CON_NAME"
sudo systemctl restart nodogsplash
# 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 "✅ 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" 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." echo "✅ Binary and assets installed to $INSTALL_DIR, and binary linked to $BIN_DIR."
# 4. Install systemd service file # 4. Install systemd service file
# Only needed for Linux systems (e.g., Raspberry Pi OS)
if [[ "$(uname)" == "Linux" ]]; then if [[ "$(uname)" == "Linux" ]]; then
echo "⚙️ Installing systemd service for Linux..." echo "⚙️ Installing systemd service for Linux..."
sudo cp timeturner.service /etc/systemd/system/ sudo cp timeturner.service /etc/systemd/system/
@ -226,14 +376,20 @@ echo ""
echo "--- Setup Complete ---" echo "--- Setup Complete ---"
echo "The TimeTurner daemon is now installed." echo "The TimeTurner daemon is now installed."
echo "The working directory is $INSTALL_DIR." 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 "" echo ""
if [[ "$(uname)" == "Linux" ]]; then if [[ "$(uname)" == "Linux" ]]; then
echo "To start the service, run:" echo "To start the service, run:"
echo " sudo systemctl start timeturner.service" echo " sudo systemctl start timeturner.service"
echo "" echo ""
echo "To view live logs, run:" echo "To view live logs, run:"
echo " journalctl -u timeturner.service -f" echo " journalctl -u tim_turner.service -f"
echo "" echo ""
fi fi
echo "To run the interactive TUI instead, simply run from the project directory:" echo "To run the interactive TUI instead, simply run from the project directory:"