From 2f8f75dfa10e938cf65cb5777d3741ac681c7d11 Mon Sep 17 00:00:00 2001 From: Djeex Date: Sun, 5 Oct 2025 15:41:11 +0200 Subject: [PATCH] 1st commit --- .gitignore | 1 + LICENSE | 20 ++++++++++ README.MD | 82 ++++++++++++++++++++++++++++++++++++++ VERSION | 1 + sh/hotdisk.sh | 46 +++++++++++++++++++++ sh/hotdisk_curl_install.sh | 11 +++++ sh/hotdisk_logger.sh | 15 +++++++ sh/install_hotdisk.sh | 75 ++++++++++++++++++++++++++++++++++ 8 files changed, 251 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.MD create mode 100644 VERSION create mode 100644 sh/hotdisk.sh create mode 100644 sh/hotdisk_curl_install.sh create mode 100644 sh/hotdisk_logger.sh create mode 100644 sh/install_hotdisk.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5032f0d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.tmp \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8a07638 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +MIT License +Copyright (c) 2025 > Djeex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..7e76611 --- /dev/null +++ b/README.MD @@ -0,0 +1,82 @@ +# HotDisk +A lightweight Linux tool that monitors **SATA HDD temperatures**, sends **Discord notifications**, and safely shuts down the system if disks overheat. + +> [!NOTE] +>_HotDisk focuses on SATA disks (NVMe ignored). The repo contains installer scripts, systemd integration, and log rotation setup._ +> _Github repo is a mirror of https://git.djeex.fr/Djeex/hotdisk. You'll find full package, history and release note there._ + +## 📌 Table of Contents + +- [✨ Features](#-features) +- [📜 Script Installation (Debian/Ubuntu)](#-script-installation-debianubuntu) +- [⚙️ Configuration Variables](#-configuration-variables) +- [🐞 Common issues](#-common-issues) +- [❓ How it works](#-how-it-works) +- [🧑‍💻 Contributors](#-contributors) + +## ✨ Features + +- Monitors SATA disk temperatures using SMART (`smartctl`). +- Configurable maximum temperature threshold. +- Counts consecutive minutes above or below threshold before notifications or shutdown. +- Sends Discord notifications when disks exceed or drop below the threshold. +- Sends pre-shutdown warning before executing system shutdown. +- Configurable logging with automatic log rotation. +- Runs as a **systemd service + timer** for continuous monitoring. + +## 📜 Script Installation (Debian/Ubuntu) + +**Requirements** + +- `bash`, `smartmontools`, `curl`, `lsblk` (Debian/Ubuntu default) +- `systemd` & `sudo` + +**Quick Install with Curl** + +```bash +curl -fsSL https://git.djeex.fr/Djeex/hotdisk/raw/branch/main/sh/hotdisk_curl_install.sh | bash +``` + +The installer will: + +- Prompt for configuration: max temperature, cooldown, Discord webhook, log file, logrotate settings. +- Check and install missing dependencies. +- Generate logrotate configuration. +- Install and enable systemd service + timer. +- Run HotDisk immediately for testing. + +**Check Logs** + +```bash +tail -f /var/log/hdd_temp_monitor.log +``` + +## ⚙️ Configuration Variables + +| Variable | Description | Default Value | +|-----------------------|-----------------------------------------------------------------|-----------------------------------------------| +| `MAX_TEMP` | Maximum allowed temperature (°C) before starting shutdown count | `60` | +| `HOT_DURATION` | Consecutive minutes above `MAX_TEMP` before shutdown | `5` | +| `COOL_DURATION` | Consecutive minutes below `MAX_TEMP` required to reset counter | `5` | +| `LOG_FILE` | Path to the main log file | `/var/log/hdd_temp_monitor.log` | +| `LOG_ROTATE_COUNT` | Number of log files to keep | `7` | +| `LOG_ROTATE_PERIOD` | Rotation period for logs (`daily` or `weekly`) | `daily` | +| `DISCORD_WEBHOOK` | Discord webhook URL for notifications | _Required_ | + +Configuration is stored in `/etc/hdd_temp_monitor.conf` and is created by the installer. + +## 🐞 Common issues + +- `smartctl` may fail if SATA disks do not support SMART. +- Incorrect Discord webhook URL: double-check for typos. +- Installer requires `sudo` privileges for shutdown, log creation, and systemd services. + +## ❓ How it works + +1. The script reads SMART temperature for all SATA disks every minute. +2. Counts consecutive minutes above/below threshold. +3. Sends Discord notifications if threshold exceeded or cooled. +4. Initiates system shutdown if temperature exceeds limit for configured duration. +5. Logs all temperatures and counter states, rotates logs automatically. + + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6c6aa7c --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file diff --git a/sh/hotdisk.sh b/sh/hotdisk.sh new file mode 100644 index 0000000..d19960e --- /dev/null +++ b/sh/hotdisk.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# HotDisk: Monitor SATA disk temperature and notify via Discord +CONF_FILE="/etc/hdd_temp_monitor.conf" +STATE_FILE="/tmp/hdd_temp_state.txt" +source "$CONF_FILE" +DISKS=$(lsblk -dno NAME,TYPE | awk '$2=="disk"{print $1}' | grep -v '^nvme') +if [ ! -f "$STATE_FILE" ]; then touch "$STATE_FILE"; fi +declare -A HOT_COUNTERS +declare -A COOL_COUNTERS +while read -r line; do + disk=$(echo "$line" | cut -d= -f1) + val=$(echo "$line" | cut -d= -f2) + HOT_COUNTERS[$disk]=$val +done < "$STATE_FILE" +for disk in $DISKS; do + temp=$(smartctl -A /dev/$disk | awk '/Temperature_Celsius/ {print $10; exit}') + [ -z "$temp" ] && continue + hot=${HOT_COUNTERS[$disk]:-0} + cool=${COOL_COUNTERS[$disk]:-0} + if [ "$temp" -ge "$MAX_TEMP" ]; then + hot=$((hot+1)) + cool=0 + curl -s -X POST -H "Content-Type: application/json" -d "{\"content\":\"🔥 Warning: $disk is above $MAX_TEMP°C for $hot minute(s)\"}" "$DISCORD_WEBHOOK" + if [ "$hot" -ge "$HOT_DURATION" ]; then + curl -s -X POST -H "Content-Type: application/json" -d "{\"content\":\"⚠️ Critical: $disk has been above $MAX_TEMP°C for $HOT_DURATION minutes. Shutting down...\"}" "$DISCORD_WEBHOOK" + sleep 5 + shutdown -h now + fi + else + if [ "$hot" -gt 0 ]; then + cool=$((cool+1)) + curl -s -X POST -H "Content-Type: application/json" -d "{\"content\":\"❄️ Notice: $disk is under $MAX_TEMP°C for $cool minute(s)\"}" "$DISCORD_WEBHOOK" + if [ "$cool" -ge "$COOL_DURATION" ]; then + hot=0 + cool=0 + fi + fi + fi + HOT_COUNTERS[$disk]=$hot + COOL_COUNTERS[$disk]=$cool + echo "$(date '+%Y-%m-%d %H:%M:%S') $disk $temp°C" >> "$LOG_FILE" +done +> "$STATE_FILE" +for disk in "${!HOT_COUNTERS[@]}"; do + echo "$disk=${HOT_COUNTERS[$disk]}" >> "$STATE_FILE" +done diff --git a/sh/hotdisk_curl_install.sh b/sh/hotdisk_curl_install.sh new file mode 100644 index 0000000..a430639 --- /dev/null +++ b/sh/hotdisk_curl_install.sh @@ -0,0 +1,11 @@ +#!/bin/bash +BASE_URL="https://git.djeex.fr/Djeex/hotdisk/raw/branch/main/sh" +SCRIPTS=("hotdisk.sh" "hotdisk_logger.sh" "install_hotdisk.sh") +sudo apt update +sudo apt install -y smartmontools curl +sudo mkdir -p /usr/local/bin +for script in "${SCRIPTS[@]}"; do + sudo curl -fsSL "$BASE_URL/$script" -o "/usr/local/bin/$script" + sudo chmod +x "/usr/local/bin/$script" +done +sudo /usr/local/bin/install_hotdisk.sh diff --git a/sh/hotdisk_logger.sh b/sh/hotdisk_logger.sh new file mode 100644 index 0000000..d434d51 --- /dev/null +++ b/sh/hotdisk_logger.sh @@ -0,0 +1,15 @@ +#!/bin/bash +CONF_FILE="/etc/hdd_temp_monitor.conf" +source "$CONF_FILE" +LOGROTATE_FILE="/etc/logrotate.d/hotdisk" +sudo tee "$LOGROTATE_FILE" > /dev/null </dev/null 2>&1; then MISSING+=("$cmd"); fi +done +if [ ${#MISSING[@]} -ne 0 ]; then + echo "❌ Missing dependencies:" + for cmd in "${MISSING[@]}"; do echo " - $cmd"; done + echo "Install missing packages: sudo apt update && sudo apt install smartmontools curl" + exit 1 +fi +echo "✅ All dependencies are installed." +read -p "Maximum temperature (°C) before shutdown [60]: " MAX_TEMP +MAX_TEMP=${MAX_TEMP:-60} +read -p "Consecutive minutes above MAX_TEMP before shutdown [5]: " HOT_DURATION +HOT_DURATION=${HOT_DURATION:-5} +read -p "Consecutive minutes below MAX_TEMP to reset counter [5]: " COOL_DURATION +COOL_DURATION=${COOL_DURATION:-5} +read -p "Log file path [/var/log/hdd_temp_monitor.log]: " LOG_FILE +LOG_FILE=${LOG_FILE:-/var/log/hdd_temp_monitor.log} +read -p "Logrotate: number of files to keep [7]: " LOG_ROTATE_COUNT +LOG_ROTATE_COUNT=${LOG_ROTATE_COUNT:-7} +read -p "Logrotate: rotation period (daily/weekly) [daily]: " LOG_ROTATE_PERIOD +LOG_ROTATE_PERIOD=${LOG_ROTATE_PERIOD:-daily} +echo "Paste your Discord Webhook URL here." +read -p "Discord Webhook URL: " DISCORD_WEBHOOK +[ -z "$DISCORD_WEBHOOK" ] && { echo "Discord Webhook cannot be empty"; exit 1; } +echo "" +echo "Please confirm:" +echo "MAX_TEMP=$MAX_TEMP" +echo "HOT_DURATION=$HOT_DURATION" +echo "COOL_DURATION=$COOL_DURATION" +echo "LOG_FILE=$LOG_FILE" +echo "LOG_ROTATE_COUNT=$LOG_ROTATE_COUNT" +echo "LOG_ROTATE_PERIOD=$LOG_ROTATE_PERIOD" +echo "DISCORD_WEBHOOK=$DISCORD_WEBHOOK" +read -p "Is this correct? (y/n): " CONFIRM +[[ ! "$CONFIRM" =~ ^[Yy]$ ]] && { echo "Aborted"; exit 1; } +sudo tee "$CONFIG_FILE" > /dev/null < /dev/null < /dev/null <