From 98e4d866ac3f81a99135b328630151796658c1e4 Mon Sep 17 00:00:00 2001 From: Samet <85709420+sametlprsln@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:44:08 +0000 Subject: [PATCH 1/2] feat(heartbeat): add heartbeat configuration and installation scripts --- config/heartbeat.conf | 63 ++++++++++++ install.sh | 13 ++- saglik/has-heartbeat.service | 6 ++ saglik/has-heartbeat.timer | 9 ++ scripts/heartbeat.sh | 182 +++++++++++++++++++++++++++++++++++ scripts/install-heartbeat.sh | 174 +++++++++++++++++++++++++++++++++ 6 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 config/heartbeat.conf create mode 100644 saglik/has-heartbeat.service create mode 100644 saglik/has-heartbeat.timer create mode 100755 scripts/heartbeat.sh create mode 100755 scripts/install-heartbeat.sh diff --git a/config/heartbeat.conf b/config/heartbeat.conf new file mode 100644 index 0000000..8c2eba3 --- /dev/null +++ b/config/heartbeat.conf @@ -0,0 +1,63 @@ +# HAS_PrepperDisk uzaktan nabız ayarları / remote heartbeat settings +# scripts/install-heartbeat.sh bu dosyayı /etc/has-heartbeat.conf'a yazar. +# It writes the settings to /etc/has-heartbeat.conf; on an installed box that file is live. +# +# url: sinyalin gideceği adres. Boş = nabız kapalı / empty = disabled. +# Değişkenler / variables: +# {status}: up | down {msg}: uyarı metni / warning text +# {box}: box_id {uptime}: örn. 3d12h / e.g. 3d12h +# {disk}: doluluk yüzdesi / disk usage percent +# {cpu}: sıcaklık, °C / temperature in °C (yoksa boş kalır / empty if unavailable) +# Examples: +# healthchecks.io : https://hc-ping.com/ format="params" +# Uptime Kuma : https:///api/push/ (push monitor) format="params" +# Discord webhook : https://discord.com/api/webhooks// format="json" +# Telegram : https://api.telegram.org/bot/sendMessage?chat_id= format="json" + +url="" + +# --- hazır biçimler / preset formats (yeni başlayanlar için / for beginners) --- +# params: sinyal ve uyarılar URL parametresi olarak gider (?status=up&msg=...) +# json: sinyal POST gövdesinde JSON olarak gider ({"content": ..., "text": ...}) +# NOT: query ya da body doluysa format yok sayılır. / if query or body is set, format is ignored. +format="params" + +# --- tam özelleştirme / full customization --- +# HTTP yöntemi; boşsa otomatik: preset biçimde params->GET, json->POST; +# query/body modunda body doluysa POST, yoksa GET. +# HTTP method; empty = auto: params->GET, json->POST in preset mode; +# in query/body mode POST when body is set, otherwise GET. +method="" + +# HTTP başlıkları / headers: +# headers=("Authorization: Bearer token" "X-Box-ID: has1") +headers=() + +# GET/POST sorgu şablonu / query template (URL'nin ? sonrası / after the ?): +# query="durum={status}&mesaj={msg}" +# Değerler otomatik percent-encode edilir / values are percent-encoded. +query="" + +# Gövde şablonu / body template, örn. / e.g.: +# body='{"durum":"{status}","mesaj":"{msg}"}' +# Değerler otomatik JSON-escape edilir / values are JSON-escaped. +body="" + +# --- veri seçimi / what to send --- +# disk.json'daki uyarılar sinyalle gitsin mi / send the disk.json warnings (1/0)? +# Uyarı varsa sinyal her durumda "down" gider; bu ayar yalnızca uyarı metninin +# sinyale eklenip eklenmeyeceğini belirler. +# If warnings exist the signal is "down" regardless; this only controls whether +# the warning text is included in the signal. +warnings=1 + +# temel metrikler de gitsin mi / also send basic metrics (1/0)? +# {uptime} {disk} {cpu} değişkenlerini doldurur / fills these variables +metrics=0 + +# isteğe bağlı kutu etiketi / optional box label, örn. "has1" +box_id="" + +# systemd zamanlayıcı aralığı / systemd timer interval: 30min, 6h, 12h, 1d ... +# Değiştirmek için install-heartbeat.sh'ı tekrar çalıştır / re-run to change. +interval="6h" diff --git a/install.sh b/install.sh index 6d6947a..1d85ec0 100755 --- a/install.sh +++ b/install.sh @@ -2,7 +2,8 @@ # HAS_PrepperDisk kurulum betiği / installer # 1. Internet-in-a-Box ayarlarını hazırlar / prepares Internet-in-a-Box settings # 2. Internet-in-a-Box'ı kurar / installs Internet-in-a-Box -# 3. HAS_PrepperDisk ana sayfasını kurar / installs the HAS_PrepperDisk homepage +# 3. Ana sayfayı, disk sağlığını ve (isteğe bağlı) heartbeat'i kurar / +# installs the homepage, disk health and (optional) heartbeat # # Kurulum sırasında Pi yeniden başlarsa bu betiği tekrar çalıştır. # If the Pi reboots during install, just run this script again. @@ -75,16 +76,22 @@ else [ -f /etc/iiab/install-flags/iiab-complete ] || die "Kurulum bitmedi / install not finished. Tekrar çalıştır / run again: sudo ./install.sh" fi -# -------------------------------------------------------------- 3. ana sayfa -say "3/3 Ana sayfa / homepage" +# -------------------------------------------------------------- 3. bileşenler +say "3/3 HAS_PrepperDisk bileşenleri / components" "$REPO/scripts/install-homepage.sh" "$REPO/scripts/install-disk-health.sh" +read -rp "Heartbeat kurulsun mu? / install heartbeat? [e/y/N] " HB +case "$HB" in + e|E|y|Y) "$REPO/scripts/install-heartbeat.sh";; + *) echo "Atlandı, sonradan kurmak için / skipped, to install later: sudo ./scripts/install-heartbeat.sh";; +esac IP=$(hostname -I | awk '{print $1}') say "Bitti / done" cat </dev/null 2>&1; then + while IFS= read -r w; do + [ -n "$w" ] && warns+=("$w") + done < <(python3 -c 'import json, sys +for w in json.load(open(sys.argv[1])).get("warnings", []): + print(w)' "$DISK_JSON" 2>/dev/null) + elif grep -q '"warnings":\[[^]]' "$DISK_JSON"; then + warns+=("disk.json uyarı içeriyor / disk.json contains warnings") + fi +else + warns+=("disk.json yok, disk sağlığı bilinmiyor / missing, disk health unknown") +fi + +status="up" +[ ${#warns[@]} -gt 0 ] && status="down" + +# message +msg="" +[ -n "$box_id" ] && msg+="[$box_id] " +if [ ${#warns[@]} -gt 0 ]; then + msg+="PROBLEM: " + for w in "${warns[@]}"; do msg+="$w | "; done + msg=${msg%" | "} +else + msg+="ok" +fi + +# metrics +m_up="" m_pct="" m_cpu="" +need=0 +[ "$metrics" = 1 ] && need=1 +case "$url $query $body" in *"{uptime}"*|*"{disk}"*|*"{cpu}"*) need=1 ;; esac +if [ "$need" = 1 ]; then + m_up=$(awk '{printf "%dd%dh", int($1/86400), int(($1%86400)/3600)}' /proc/uptime 2>/dev/null) + m_pct=$(df --output=pcent /library 2>/dev/null | tail -1 | tr -dc '0-9') + [ -r /sys/class/thermal/thermal_zone0/temp ] && m_cpu=$(( $(cat /sys/class/thermal/thermal_zone0/temp) / 1000 )) +fi +extra="" +if [ "$metrics" = 1 ]; then + extra=" | uptime ${m_up:-?}, disk %${m_pct:-?}" + [ -n "$m_cpu" ] && extra+=", CPU ${m_cpu}°C" +fi +msg+="$extra" + +# escaping +json_esc(){ + if command -v python3 >/dev/null 2>&1; then + python3 -c 'import json, sys +sys.stdout.write(json.dumps(sys.argv[1])[1:-1])' "$1" + return + fi + local s="$1" + s=${s//\\/\\\\} + s=${s//\"/\\\"} + s=${s//$'\n'/\\n} + s=${s//$'\r'/\\r} + s=${s//$'\t'/\\t} + printf '%s' "$s" +} + +pct_esc(){ + if command -v python3 >/dev/null 2>&1; then + python3 -c 'import sys, urllib.parse +sys.stdout.write(urllib.parse.quote_plus(sys.argv[1]))' "$1" + return + fi + local s="$1" out="" bytes hex i c + bytes=$(printf '%s' "$s" | od -An -v -tx1 | tr -d ' \n') + for ((i=0; i<${#bytes}; i+=2)); do + hex=${bytes:i:2} + printf -v c '%b' "\\x$hex" + case "$c" in + [a-zA-Z0-9.~_-]) out+="$c" ;; + ' ') out+="+" ;; + *) out+="%$hex" ;; + esac + done + printf '%s' "$out" +} + +subst(){ + local esc="$1" t="$2" out="" i=1 c rest k v + while [ "$i" -le "${#t}" ]; do + c=${t:i-1:1} + if [ "$c" = "{" ]; then + rest=${t:i-1} + for k in status msg box uptime disk cpu; do + if [[ "$rest" == "{$k}"* ]]; then + case "$k" in + status) v=$("$esc" "$status") ;; + msg) v=$("$esc" "$msg") ;; + box) v=$("$esc" "$box_id") ;; + uptime) v=$("$esc" "$m_up") ;; + disk) v=$("$esc" "$m_pct") ;; + cpu) v=$("$esc" "$m_cpu") ;; + esac + out+="$v" + i=$(( i + ${#k} + 2 )) + continue 2 + fi + done + fi + out+="$c" + i=$(( i + 1 )) + done + printf '%s' "$out" +} + +case "$url" in *"{"*) url=$(subst pct_esc "$url") ;; esac + +# send heartbeat +sent=1 +if [ -n "$query" ] || [ -n "$body" ]; then + # customization + args=(-fsS -m "$TIMEOUT" -o /dev/null) + for h in "${headers[@]}"; do args+=(-H "$h"); done + [ -n "$method" ] && args+=(-X "$method") + if [ -n "$body" ]; then + ct=1 + for h in "${headers[@]}"; do + [[ "${h,,}" == content-type:* ]] && ct=0 + done + [ "$ct" = 1 ] && args+=(-H 'Content-Type: application/json') + args+=(--data-binary "$(subst json_esc "$body")") + fi + u="$url" + if [ -n "$query" ]; then + q=$(subst pct_esc "$query") + case "$u" in *"?"*) u="$u&$q" ;; *) u="$u?$q" ;; esac + fi + if curl "${args[@]}" "$u"; then sent=0; fi +elif [ "$format" = params ]; then + args=(-G -fsS -m "$TIMEOUT" -o /dev/null + --data-urlencode "status=$status" --data-urlencode "msg=$msg") + [ -n "$box_id" ] && args+=(--data-urlencode "box=$box_id") + for h in "${headers[@]}"; do args+=(-H "$h"); done + if curl "${args[@]}" "$url"; then sent=0; fi +else + if command -v python3 >/dev/null 2>&1; then + body_json=$(python3 -c 'import json, sys +print(json.dumps({"content": sys.argv[1], "text": sys.argv[1]}))' "$msg") + else + esc=${msg//\\/\\\\} + esc=${esc//\"/\\\"} + body_json="{\"content\":\"$esc\",\"text\":\"$esc\"}" + fi + args=(-fsS -m "$TIMEOUT" -o /dev/null -H 'Content-Type: application/json' + --data-binary "$body_json") + [ -n "$method" ] && args+=(-X "$method") + for h in "${headers[@]}"; do args+=(-H "$h"); done + if curl "${args[@]}" "$url"; then sent=0; fi +fi + +if [ "$sent" -eq 0 ]; then + echo "heartbeat: sinyal gitti / signal sent ($status)" +else + echo "heartbeat: gönderilemedi, kutu internetsiz olabilir / not sent, box is probably offline" +fi +exit 0 diff --git a/scripts/install-heartbeat.sh b/scripts/install-heartbeat.sh new file mode 100755 index 0000000..63a72b3 --- /dev/null +++ b/scripts/install-heartbeat.sh @@ -0,0 +1,174 @@ +#!/usr/bin/env bash +# Heartbeat servisini kurar ya da günceller. Tekrar çalıştırmak güvenlidir; +# mevcut ayarlar soruların varsayılanı olur (Enter = değeri koru). +# Installs or updates the heartbeat service. Safe to re-run; current +# settings become the question defaults (Enter = keep the value). +# +# Kullanım / usage: sudo ./scripts/install-heartbeat.sh +# Ayar dosyası / settings file: /etc/has-heartbeat.conf +set -euo pipefail + +REPO="$(cd "$(dirname "$0")/.." && pwd)" +CONF=/etc/has-heartbeat.conf + +[ "$EUID" -eq 0 ] || { echo "sudo ile çalıştır / run with sudo" >&2; exit 1; } + +# shellcheck disable=SC2034 +url="" format="params" method="" query="" body="" +warnings=1 metrics=0 box_id="" interval="6h" +headers=() +# shellcheck disable=SC1090,SC1091 +[ -f "$CONF" ] && . "$CONF" + +clean(){ + local s="$1" + s=${s//\"/} + s=${s//\\/} + printf '%s' "$s" +} + +shq(){ + local s="$1" + s=${s//\'/\'\\\'\'} + printf "'%s'" "$s" +} + +ask(){ + local __var="$1" __cur a + __cur=$(clean "${!1}") + if ! read -rp "$2 [$__cur]: " a; then + echo + echo "Girdi yok, çıkılıyor / no input, exiting" >&2 + exit 1 + fi + printf -v "$__var" '%s' "$(clean "${a:-$__cur}")" +} + +ask_raw(){ + local __var="$1" __cur a + __cur=${!1} + if ! read -rp "$2 [$__cur]: " a; then + echo + echo "Girdi yok, çıkılıyor / no input, exiting" >&2 + exit 1 + fi + printf -v "$__var" '%s' "${a:-$__cur}" +} + +say(){ printf '\n\033[1m== %s\033[0m\n' "$*"; } + +# questions +say "Heartbeat" +echo "Kutu internete çıktığında bu adrese 'çalışıyorum' sinyali yollar." +echo "When the box has internet it sends an 'I am working' signal to this URL." +echo "Enter = koru/değiştirme, 'off' = kapat / Enter = keep current, 'off' = disable" +ask url "Heartbeat URL ('off' = kapat / disable)" + +if [ -z "$url" ] || [ "$url" = off ] || [ "$url" = kapat ]; then + url="" + hlist="" + for h in "${headers[@]}"; do hlist+=" $(shq "$h")"; done + { + printf '# HAS_PrepperDisk heartbeat (kapalı / disabled)\n' + printf 'url=""\n' + printf 'format=%s\nmethod=%s\n' "$(shq "$format")" "$(shq "$method")" + printf 'headers=(%s)\n' "${hlist# }" + printf 'query=%s\nbody=%s\n' "$(shq "$query")" "$(shq "$body")" + printf 'warnings=%s\nmetrics=%s\n' "$warnings" "$metrics" + printf 'box_id="%s"\ninterval="%s"\n' "$box_id" "$interval" + } > "$CONF" + chmod 600 "$CONF" + if systemctl list-unit-files has-heartbeat.timer --no-legend 2>/dev/null | grep -q .; then + systemctl disable --now has-heartbeat.timer >/dev/null + rm -f /etc/systemd/system/has-heartbeat.service /etc/systemd/system/has-heartbeat.timer + systemctl daemon-reload + say "Heartbeat kapatıldı / heartbeat disabled" + else + say "Heartbeat kurulmadı / heartbeat not installed" + fi + exit 0 +fi + +while :; do + ask format "Biçim / format (params=healthchecks.io, Uptime Kuma etc...) (json=Discord, Telegram etc...)" + case "$format" in params|json) break;; *) echo "params ya da json yazın / enter params or json";; esac +done +while :; do + ask warnings "Disk uyarıları yollansın mı / send disk warnings (1/0)" + case "$warnings" in 1|0) break;; *) echo "1 ya da 0";; esac +done +while :; do + ask metrics "Metrikler yollansın mı (uptime, disk, sıcaklık) / send metrics (1/0)" + case "$metrics" in 1|0) break;; *) echo "1 ya da 0";; esac +done +ask box_id "Kutu etiketi / box label (isteğe bağlı / optional)" +while :; do + ask interval "Aralık / interval" + case "$interval" in *[!0-9smhdw]*) ;; *) case "$interval" in *[smhdw]) break;; esac;; esac + echo "systemd süresi yazın, örn. 6h / enter a systemd span, e.g. 6h" +done + +# customization +say "Tam özelleştirme / full customization (boş bırakılırsa format kullanılır)" +echo "Değişkenler / variables: {status} {msg} {box} {uptime} {disk} {cpu}" +while :; do + ask method "HTTP yöntemi / method (GET, POST etc...; boş = otomatik / empty = auto)" + case "$method" in + '') break;; + *[!A-Za-z]*) ;; + *) break;; + esac +done + +if [ ${#headers[@]} -gt 0 ]; then + echo "Mevcut header'lar / current headers:" + i=1 + for h in "${headers[@]}"; do echo " $i. $h"; i=$(( i + 1 )); done + read -rp "Korunsun mu? Enter=koru, h=yeniden gir / keep? Enter=keep, h=re-enter: " a || a="" + [ "$a" = h ] && headers=() +fi +while :; do + read -rp " header ekle (bitirmek için boş Enter) / add header (empty Enter to finish): " h || h="" + [ -z "$h" ] && break + headers+=("$h") +done + +ask_raw query "Sorgu şablonu / query template, örn. durum={status}&mesaj={msg}" +ask_raw body "Gövde şablonu / body template, örn. {\"durum\":\"{status}\",\"mesaj\":\"{msg}\"}" + +hlist="" +for h in "${headers[@]}"; do hlist+=" $(shq "$h")"; done +{ + printf '# HAS_PrepperDisk heartbeat ayarları / settings\n' + printf '# Düzenlenebilir / editable: url, format, method, headers, query, body,\n' + printf '# warnings, metrics, box_id. Aralık için betiği tekrar çalıştır /\n' + printf '# re-run install-heartbeat.sh for interval.\n' + printf 'url="%s"\n' "$url" + printf 'format=%s\n' "$(shq "$format")" + printf 'method=%s\n' "$(shq "$method")" + printf 'headers=(%s)\n' "${hlist# }" + printf 'query=%s\n' "$(shq "$query")" + printf 'body=%s\n' "$(shq "$body")" + printf 'warnings=%s\nmetrics=%s\n' "$warnings" "$metrics" + printf 'box_id="%s"\ninterval="%s"\n' "$box_id" "$interval" +} > "$CONF" +chmod 600 "$CONF" + +# systemd units +for u in has-heartbeat.service has-heartbeat.timer; do + sed -e "s#@REPO@#$REPO#g" -e "s#@INTERVAL@#$interval#g" "$REPO/saglik/$u" > "/etc/systemd/system/$u" + chmod 644 "/etc/systemd/system/$u" +done +systemctl daemon-reload +systemctl enable --now has-heartbeat.timer >/dev/null + +say "Kuruldu / installed" +echo "Ayar / settings: $CONF" +echo "Test için / to test now:" +echo " sudo $REPO/scripts/heartbeat.sh" +echo "Kayıtlar / logs:" +echo " journalctl -u has-heartbeat.service" +echo "Değiştirmek için tekrar çalıştır / to change, re-run:" +echo " sudo $REPO/scripts/install-heartbeat.sh" +echo "İlk sinyal şimdi gönderiliyor / sending the first signal now:" +"$REPO/scripts/heartbeat.sh" From df79671c3fc93de643f272ec152f9393b11ecf34 Mon Sep 17 00:00:00 2001 From: Samet <85709420+sametlprsln@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:48:48 +0000 Subject: [PATCH 2/2] docs(heartbeat): add heartbeat feature documentation to README --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index a2f6fba..363fe99 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,32 @@ Every 6 hours (and 5 minutes after boot) `scripts/disk-health.sh` checks the `/l Check now: `sudo ./scripts/disk-health.sh`. Disks behind some USB adapters don't report SMART; those checks are then skipped silently. +### Heartbeat (optional) + +When the box connects to the internet, it sends a “I’m alive” signal to a service of your choice. If the signals stop arriving for a certain period, that service sends an alert, allowing you to remotely detect that the box has gone down. + +```bash +sudo ./scripts/install-heartbeat.sh +``` + +When the script is run again, the existing settings become the default answers to the prompts. Press Enter to keep the current value. Settings are stored in `/etc/has-heartbeat.conf`. You can manually edit `url`, `format`, `method`, `headers`, `query`, `body`, `warnings`, `metrics`, and `box_id` (changes take effect with the next heartbeat). To change `interval`, you must run the script again. +To disable the feature, run the script again and enter `off` when prompted for the URL. +To test: `sudo ./scripts/heartbeat.sh` +Logs: `journalctl -u has-heartbeat.service` + +For a custom API, configure `method`, `headers`, and a `query` or `body` template in `/etc/has-heartbeat.conf`. +The following variables are replaced with escaped values: +`{status}` (up/down), `{msg}`, `{box}`, `{uptime}`, `{disk}` (%), `{cpu}` (°C) + +```bash +url="https://monitor.example.com/api/box" +method="POST" +headers=("Authorization: Bearer token") +body='{"status":"{status}","message":"{msg}"}' +``` + +`query` builds the part after the `?` of the URL (e.g. `query="durum={status}&mesaj={msg}"`), `body` becomes the request body, and `method` defaults to GET for `params`, POST for `json` and POST when `body` is set. Values in `query` are percent-encoded and values in `body` are JSON-escaped automatically. When `query` or `body` is set, `format` is ignored. + ### Repo layout ``` @@ -118,8 +144,10 @@ scripts/download-content.sh downloads/updates ZIM files from Kiwix scripts/install-homepage.sh installs the custom homepage scripts/status.sh health check: disk, services, hotspot, content, power scripts/disk-health.sh disk and power health check (saglik/: its systemd timer) +scripts/install-heartbeat.sh (optional) installs the heartbeat config/iiab-overrides.yml Internet-in-a-Box settings config/content.conf list of content to download +config/heartbeat.conf heartbeat settings www/home/index.html homepage www/home/acil.html emergency page (Turkish, sourced from AFAD and EPA) ``` @@ -161,6 +189,7 @@ It checks free space on the SD card and SSD, the web, Kiwix, hotspot and DHCP se `br0` should now be UP with 10.10.10.10 and `wlan0` should show `state forwarding`. - **SSH without a cable:** join the Pi's hotspot and use `ssh user@10.10.10.10`. - **Restoring the original homepage:** `sudo cp /library/www/html/home/index.html.iiab-original /library/www/html/home/index.html` +- **No heartbeat signal arrives.** While the box is offline that is normal. When it has internet, test with `sudo ./scripts/heartbeat.sh` and check `journalctl -u has-heartbeat.service -n 20`. If `/etc/has-heartbeat.conf` has an empty `url`, the heartbeat is disabled; re-run `sudo ./scripts/install-heartbeat.sh`. ### License @@ -247,6 +276,27 @@ Pi'nin dahili Wi-Fi kartı sadece hotspot için kullanılıyor. Pi'nin geçici o Hemen kontrol: `sudo ./scripts/disk-health.sh`. Bazı USB adaptörlerinin arkasındaki diskler SMART bilgisi vermez; o zaman bu kontrol sessizce atlanır. +### Heartbeat (isteğe bağlı) + +Kutu internete çıktığında seçtiğin bir servise "çalışıyorum" sinyali yollar. Sinyaller belirli süre gelmezse o servis uyarır ve kutunun düştüğünü uzaktan öğrenirsin. + +```bash +sudo ./scripts/install-heartbeat.sh +``` + +Betik tekrar çalıştırıldığında mevcut ayarlar soruların varsayılanı olur; değeri korumak için Enter'a bas. Ayarlar `/etc/has-heartbeat.conf` dosyasında durur. `url`, `format`, `method`, `headers`, `query`, `body`, `warnings`, `metrics` ve `box_id` elle düzenlenebilir (bir sonraki sinyalde geçerli olur), `interval`'ı değiştirmek için betiği tekrar çalıştırmak gerekir. Özelliği kapatmak için betiği tekrar çalıştır ve URL sorusuna `off` yaz. +Test: `sudo ./scripts/heartbeat.sh`. +Loglar: `journalctl -u has-heartbeat.service`. + +Özel bir API için `/etc/has-heartbeat.conf` dosyasında `method`, `headers` ve bir `query` ya da `body` şablonu belirle. `{status}` (up/down), `{msg}`, `{box}`, `{uptime}`, `{disk}` (%) ve `{cpu}` (°C) değişkenleri escaped değerlerle değiştirilir: + +```bash +url="https://monitor.example.com/api/box" +method="POST" +headers=("Authorization: Bearer token") +body='{"durum":"{status}","mesaj":"{msg}"}' +``` + ### Repo yapısı ``` @@ -256,8 +306,10 @@ scripts/download-content.sh Kiwix'ten ZIM dosyalarını indirir/günceller scripts/install-homepage.sh özel ana sayfayı kurar scripts/status.sh sağlık kontrolü: disk, servisler, hotspot, içerik, güç scripts/disk-health.sh disk ve güç sağlığı denetimi (saglik/: systemd zamanlayıcısı) +scripts/install-heartbeat.sh (isteğe bağlı) heartbeat kurar config/iiab-overrides.yml Internet-in-a-Box ayarları config/content.conf indirilecek içerik listesi +config/heartbeat.conf heartbeat ayarları www/home/index.html ana sayfa www/home/acil.html acil durum sayfası (AFAD ve EPA kaynaklı) ``` @@ -299,6 +351,7 @@ SD kart ve SSD'deki boş alanı, web, Kiwix, hotspot ve DHCP servislerini, hotsp Artık `br0` 10.10.10.10 adresiyle UP, `wlan0` da `state forwarding` görünmeli. - **Kablosuz SSH:** Pi'nin hotspot'una bağlan ve `ssh kullanici@10.10.10.10` kullan. - **Orijinal ana sayfaya dönmek için:** `sudo cp /library/www/html/home/index.html.iiab-original /library/www/html/home/index.html` +- **Heartbeat sinyali gitmiyor.** Kutu internetsizken bu normaldir. İnterneti olduğunda `sudo ./scripts/heartbeat.sh` ile test et ve `journalctl -u has-heartbeat.service -n 20` kaydına bak. `/etc/has-heartbeat.conf` içinde `url` boşsa nabız kapalıdır; `sudo ./scripts/install-heartbeat.sh`'ı tekrar çalıştır. ### Lisans