1st commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.tmp
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -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.
|
82
README.MD
Normal file
82
README.MD
Normal file
@@ -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.
|
||||
|
||||
|
46
sh/hotdisk.sh
Normal file
46
sh/hotdisk.sh
Normal file
@@ -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
|
11
sh/hotdisk_curl_install.sh
Normal file
11
sh/hotdisk_curl_install.sh
Normal file
@@ -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
|
15
sh/hotdisk_logger.sh
Normal file
15
sh/hotdisk_logger.sh
Normal file
@@ -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 <<EOF
|
||||
$LOG_FILE {
|
||||
$LOG_ROTATE_PERIOD
|
||||
rotate $LOG_ROTATE_COUNT
|
||||
compress
|
||||
missingok
|
||||
notifempty
|
||||
copytruncate
|
||||
}
|
||||
EOF
|
||||
echo "Logrotate configuration generated at $LOGROTATE_FILE"
|
75
sh/install_hotdisk.sh
Normal file
75
sh/install_hotdisk.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
CONFIG_FILE=/etc/hdd_temp_monitor.conf
|
||||
SERVICE_FILE=/etc/systemd/system/hotdisk.service
|
||||
TIMER_FILE=/etc/systemd/system/hotdisk.timer
|
||||
echo "=== HotDisk Installation ==="
|
||||
DEPENDENCIES=(bash smartctl curl lsblk awk date tee sudo systemctl)
|
||||
MISSING=()
|
||||
for cmd in "${DEPENDENCIES[@]}"; do
|
||||
if ! command -v "$cmd" >/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 <<EOF
|
||||
MAX_TEMP=$MAX_TEMP
|
||||
HOT_DURATION=$HOT_DURATION
|
||||
COOL_DURATION=$COOL_DURATION
|
||||
LOG_FILE=$LOG_FILE
|
||||
LOG_ROTATE_COUNT=$LOG_ROTATE_COUNT
|
||||
LOG_ROTATE_PERIOD=$LOG_ROTATE_PERIOD
|
||||
DISCORD_WEBHOOK=$DISCORD_WEBHOOK
|
||||
EOF
|
||||
sudo chmod +x /usr/local/bin/sh/hotdisk.sh /usr/local/bin/sh/hotdisk_logger.sh
|
||||
sudo /usr/local/bin/sh/hotdisk_logger.sh
|
||||
sudo tee "$SERVICE_FILE" > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=HotDisk SATA Temperature Check
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/sh/hotdisk.sh
|
||||
EOF
|
||||
sudo tee "$TIMER_FILE" > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Run HotDisk temperature check every minute
|
||||
[Timer]
|
||||
OnBootSec=1min
|
||||
OnUnitActiveSec=1min
|
||||
Persistent=true
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now hotdisk.timer
|
||||
sudo /usr/local/bin/sh/hotdisk.sh
|
||||
echo "✅ HotDisk installation complete!"
|
Reference in New Issue
Block a user