diff --git a/README.md b/README.md index 8a7b357..6a46e29 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,17 @@ Created by Chris Frankland-Wright and John Rogers - Broadcasts time via local NTP server - Supports configurable time offsets (hours, minutes, seconds, frames or milliseconds) - Systemd service support for headless operation +- Web-based UI for monitoring and control when running as a daemon + +--- + +## 🖥️ Web Interface & API + +When running as a background daemon, TimeTurner provides a web interface for monitoring and configuration. + +- **Access**: The web UI is available at `http://:8080`. +- **Functionality**: You can view the real-time sync status, see logs, and change all configuration options directly from your browser. +- **API**: A JSON API is also exposed for programmatic access. See `docs/api.md` for full details. --- @@ -37,19 +48,42 @@ Created by Chris Frankland-Wright and John Rogers --- -## 🚀 Installation (to update) +## 🚀 Installation -For Rust install you can do -```bash -cargo install --git https://github.com/cjfranko/NTP-Timeturner -``` -Clone and run the installer: +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. -```bash -wget https://raw.githubusercontent.com/cjfranko/NTP-Timeturner/master/setup.sh -chmod +x setup.sh -./setup.sh -``` +### 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/). + +### Running the Installer + +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 + ``` + +### 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**: + - 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**: + - Copies the `timeturner.service` file to `/etc/systemd/system/`. + - Enables the service to start automatically on system boot. + +After installation is complete, the script will provide instructions to start the service manually or to run the application in its interactive terminal mode. --- ## 🕰️ Chrony NTP diff --git a/setup.sh b/setup.sh index 4dd5685..b8d556f 100644 --- a/setup.sh +++ b/setup.sh @@ -21,11 +21,13 @@ echo "🔧 Creating directories..." sudo mkdir -p $INSTALL_DIR echo "✅ Directory $INSTALL_DIR created." -# 3. Install binary -echo "🚀 Installing timeturner binary..." +# 3. Install binary and static web files +echo "🚀 Installing timeturner binary and web assets..." sudo cp target/release/ntp_timeturner $INSTALL_DIR/timeturner +# The static directory contains the web UI files +sudo cp -r static $INSTALL_DIR/ sudo ln -sf $INSTALL_DIR/timeturner $BIN_DIR/timeturner -echo "✅ Binary installed to $INSTALL_DIR and linked to $BIN_DIR." +echo "✅ Binary and assets installed to $INSTALL_DIR, and binary linked to $BIN_DIR." # 4. Install systemd service file if [[ "$(uname)" == "Linux" ]]; then diff --git a/src/main.rs b/src/main.rs index ab9fa94..8006681 100644 --- a/src/main.rs +++ b/src/main.rs @@ -193,11 +193,13 @@ async fn main() { }); } - // 5️⃣ Spawn UI or setup daemon logging + // 5️⃣ Spawn UI or setup daemon logging. The web service is only started + // when running as a daemon. The TUI is for interactive foreground use. if args.command.is_none() { + // --- Interactive TUI Mode --- log::info!("🔧 Watching config.yml..."); log::info!("🚀 Serial thread launched"); - log::info!("🖥️ UI thread launched"); + log::info!("🖥️ UI thread launched"); let ui_state = ltc_state.clone(); let config_clone = config.clone(); let port = serial_port_path; @@ -205,8 +207,10 @@ async fn main() { start_ui(ui_state, port, config_clone); }); } else { + // --- Daemon Mode --- // In daemon mode, logging is already set up to go to stderr. - // The systemd service will capture it. + // The systemd service will capture it. The web service (API and static files) + // is launched later in the main async block. log::info!("🚀 Starting TimeTurner daemon..."); } @@ -282,7 +286,10 @@ async fn main() { let local = LocalSet::new(); local .run_until(async move { - // 8️⃣ Spawn the API server thread + // 8️⃣ Spawn the API server task. + // This server provides the JSON API and serves the static web UI files + // from the `static/` directory. It runs in both TUI and daemon modes, + // but is primarily for the web UI used in daemon mode. { let api_state = ltc_state.clone(); let config_clone = config.clone(); diff --git a/static/index.html b/static/index.html index 7178fb9..deb683d 100644 --- a/static/index.html +++ b/static/index.html @@ -62,71 +62,71 @@

Controls

-
- - + + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+ +
+ + + + +
-
- - -
-
- -
-
- - +
+ + +
+
+ Logs Icon +

Logs

-
- - -
-
- - -
-
- - -
-
- - +
+

                         
-
- - - -
-
- - - - - -
-
- - - - -
-
-
- - -
-
- Logs Icon -

Logs

-
-
-

-                
-
-