Files
mission-control-v2/deploy/notify.sh
T
HitonabiandClaude Opus 5.5 3d8df1c6fd einstellungen: Zeitfenster, Radar-Schalter, Telegram-Test, Software-Stand und Altreste
Einstellungen, die etwas einstellen (services/einstellungen.py, /api/einstellungen):
- Update-Zeitfenster: Wochentag und Uhrzeit des Update-Laufs als Drop-in
  mc2-autoupdate.timer.d/zeitfenster.conf. Gegen die Nachhol-Falle von
  Persistent=true (24.09.): Timer vor dem daemon-reload stoppen, Stempel auf
  jetzt, dann starten. Bei Fehler zurück auf das alte Drop-in. Während eines
  Update-Laufs abgelehnt.
- Neustart nur im eingestellten Fenster (deploy/wartungsfenster.sh, drei
  Stunden ab der vollen Stunde des Beginns; Standard So 04:00-06:59).
- Radar an/aus: disable --now bzw. enable + Stempel + start (kein Nachholen).
  deploy.sh respektiert den Schalter und startet den Radar-Timer nur mit
  Stempel; das Zeitfenster-Drop-in fasst er nie an.
- Wächter: schläft der Timer eines Timer-Dienstes, ist ein alter Fehlschlag
  kein Befund mehr (der Dienst selbst ist static und schläft nie).
- Telegram-Test je Instanz (/api/einstellungen/telegram-test und
  /api/homelab/einstellungen/telegram-test) über notify.sh -d; Ergebnis und
  Grund aus dem Melde-Log. notify.sh schreibt jetzt auch den Grund des
  gescheiterten Zweitwegs in den FALLBACK-Eintrag.
- Einstellungsdatei mc2-einstellungen.json im Datenordner.

Software-Stand: deploy.sh und homelab/ausrollen.sh schreiben nach dem
Umschalten mc2-stand.json (deploy/stand-schreiben.py); /api/instanz liefert
den Stand, die Einstellungen zeigen beide Instanzen und warnen bei Abweichung.
Ohne Datei aus git, sonst unbekannt.

Aufräumen: Altreste neben dem Betrieb aus einer festen, auf der Box geprüften
Liste (Größe, Hinweis, nur was da und nicht in Gebrauch ist). Löschen nur per
Kennung und Klick mit Rückfrage; Worktrees mit git worktree prune, Alt-Units
mit daemon-reload, /opt/llamacpp notfalls mit sudo -n.

Tests: pytest mit einem systemd-Abbild samt Nachhol-Regel, echtem notify.sh
(Ersatz-Hermes, Tmp-Zugang, lokale Bot-API), Shell-Funktionen des
Wartungsfensters und von deploy.sh; vitest für die Rückfragen der Schublade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 20:37:30 +02:00

154 lines
6.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Meldeweg der Box (Autonomie E1): eine Nachricht an den User schicken.
# Primär: hermes send → Telegram (nutzt Gateway-Credentials, kein LLM nötig).
# Zweitweg (seit 24.09.2026): direkt an die Telegram-Bot-API mit den Zugangsdaten aus Hermes' .env —
# greift, wenn Hermes steht oder fehlt (die Homelab-Instanz hat gar kein Hermes).
# Letzter Ausweg: Logfile + wall.
#
# Nutzung: notify.sh "Nachricht" (oder via stdin: echo msg | notify.sh)
# notify.sh -s "[Update]" "Text" (Betreffzeile voranstellen)
# notify.sh -d -s "[Update]" "…" (dringend: geht auch nachts sofort raus)
#
# Nachtruhe (User-Entscheid 24.09.2026): Zwischen 00:00 und 06:59 wird alles, was nicht dringend
# ist, in der Nacht-Warteschlange gesammelt und um 07:00 von morgenmeldung.sh als EINE Meldung
# verschickt. Dringend ist: -d, ein Betreff mit „Alarm“/„Notfall“ oder ein Text, der mit
# „KRITISCH“ beginnt. (Bis 24.09. lieferte niemand die Warteschlange aus — seit dem 21.08.
# gingen so alle Nachtmeldungen verloren, auch die Sonntags-Updates.)
#
# Exit 0 = zugestellt (Telegram, Fallback-Log oder Nacht-Warteschlange).
# MC_NOTIFY_STRICT=1: Exit 1, wenn Telegram scheitert (für morgenmeldung.sh, damit nichts verloren geht).
# Test-Schalter: MC_NOTIFY_STUNDE (Stunde vortäuschen), MC_NIGHT_QUEUE, MC_NOTIFY_HERMES (hermes-Befehl),
# MC_TELEGRAM_ENV (Datei mit TELEGRAM_BOT_TOKEN/TELEGRAM_HOME_CHANNEL), MC_TELEGRAM_API (Bot-API-Adresse),
# MC_NOTIFY_OHNE_WALL=1 (kein wall im letzten Ausweg).
set -uo pipefail
LOG="${MC_NOTIFY_LOG:-$HOME/mc2-notify.log}"
NIGHT_QUEUE="${MC_NIGHT_QUEUE:-$HOME/.hermes/night-queue.txt}"
HERMES_BIN="${MC_NOTIFY_HERMES:-hermes}"
TG_ENV="${MC_TELEGRAM_ENV:-$HOME/.hermes/.env}"
TG_API="${MC_TELEGRAM_API:-https://api.telegram.org}"
SUBJECT=""
DRINGEND=0
while getopts ":s:d" opt; do
case "$opt" in
s) SUBJECT="$OPTARG" ;;
d) DRINGEND=1 ;;
*) echo "usage: notify.sh [-d] [-s subject] <nachricht>" >&2; exit 2 ;;
esac
done
shift $((OPTIND - 1))
MSG="${1:-}"
[ -z "$MSG" ] && [ ! -t 0 ] && MSG="$(cat)"
if [ -z "$MSG" ]; then
# Bei leerer Pipe-Eingabe lautlos beenden (wichtig für Cron-Skripte ohne Ausgabe)
exit 0
fi
TS="$(date '+%Y-%m-%d %H:%M:%S')"
# Lucy-Briefkasten (Proaktivität A3): Meldung zusätzlich an MC2 spiegeln — die Desktop-Lucy
# spricht sie dann von sich aus. Best-effort (darf den Telegram-Weg nie aufhalten).
# MC_NOTIFY_NO_ANNOUNCE=1 unterdrückt das (der Health-Wächter legt seine Einträge selbst ab).
if [ "${MC_NOTIFY_NO_ANNOUNCE:-0}" != "1" ]; then
curl -sf -m 3 -X POST "${MC_ANNOUNCE_URL:-http://127.0.0.1:9001/api/voice/announce}" \
-H 'Content-Type: application/json' \
--data "$(python3 - "$SUBJECT" "$MSG" <<'PY'
import json, sys
print(json.dumps({"text": sys.argv[2], "subject": sys.argv[1], "source": "notify"}))
PY
)" >/dev/null 2>&1 || true
fi
# Dringend ist, was nicht bis zum Morgen warten darf.
case "${SUBJECT,,}" in
*alarm*|*notfall*) DRINGEND=1 ;;
esac
case "$MSG" in
KRITISCH*) DRINGEND=1 ;;
esac
# Nachtruhe: 00:00–06:59 sammeln, außer es ist dringend. 10#… verhindert, dass „08“/„09“ als
# Oktalzahl gelesen werden.
HOUR="${MC_NOTIFY_STUNDE:-$(date +%H)}"
if [ "$DRINGEND" != "1" ] && [ "$((10#$HOUR))" -lt 7 ]; then
mkdir -p "$(dirname "$NIGHT_QUEUE")"
printf -- '- %s%s\n' "${SUBJECT:+$SUBJECT: }" "$MSG" >> "$NIGHT_QUEUE"
# Wortlaut „QUEUED für Morgen-Digest“ nicht ändern: services/update_verlauf.py liest ihn.
echo "$TS QUEUED für Morgen-Digest: $MSG" >> "$LOG"
exit 0
fi
# Primärweg: Telegram via hermes send (Login-Shell-PATH, falls aus Timer/cron aufgerufen).
if [ -n "$SUBJECT" ]; then
SEND_OUT="$(bash -lc '"$1" send --to telegram --subject "$2" -- "$3"' _ "$HERMES_BIN" "$SUBJECT" "$MSG" 2>&1)"
else
SEND_OUT="$(bash -lc '"$1" send --to telegram -- "$2"' _ "$HERMES_BIN" "$MSG" 2>&1)"
fi
if [ $? -eq 0 ]; then
echo "$TS OK telegram: $MSG" >> "$LOG"
exit 0
fi
# Zweitweg: direkt an die Bot-API. Das Token geht über --config auf stdin an curl, damit es nicht
# in der Prozessliste steht.
env_wert() {
local wert
wert="$(grep -E "^(export +)?$1=" "$TG_ENV" 2>/dev/null | tail -n 1)"
wert="${wert#*=}"
wert="${wert%$'\r'}"
wert="${wert%\"}"; wert="${wert#\"}"
wert="${wert%\'}"; wert="${wert#\'}"
printf '%s' "$wert"
}
# Warum der Zweitweg scheiterte, steht seit 24.09.2026 mit im FALLBACK-Eintrag (der Telegram-Test der Oberfläche
# zeigt es an). Ohne Klammern im Text: services/update_verlauf.py trennt den Eintrag an „): “.
DIREKT_GRUND=""
telegram_direkt() {
local token chat thread text rc
if [ ! -r "$TG_ENV" ]; then
DIREKT_GRUND="Zugangsdatei $TG_ENV fehlt oder ist nicht lesbar"
return 1
fi
token="$(env_wert TELEGRAM_BOT_TOKEN)"
chat="$(env_wert TELEGRAM_HOME_CHANNEL)"
thread="$(env_wert TELEGRAM_HOME_CHANNEL_THREAD_ID)"
if [ -z "$token" ] || [ -z "$chat" ]; then
DIREKT_GRUND="TELEGRAM_BOT_TOKEN oder TELEGRAM_HOME_CHANNEL fehlt in $TG_ENV"
return 1
fi
text="$MSG"
[ -n "$SUBJECT" ] && text="$SUBJECT
$MSG"
printf 'url = "%s/bot%s/sendMessage"\n' "$TG_API" "$token" \
| curl -sf -m 15 -o /dev/null --config - \
--data-urlencode "chat_id=$chat" --data-urlencode "text=$text" \
${thread:+--data-urlencode "message_thread_id=$thread"}
rc=$?
case "$rc" in
0) return 0 ;;
22) DIREKT_GRUND="Telegram lehnt ab, HTTP-Fehler – Token oder Chat falsch?" ;;
6|7) DIREKT_GRUND="Telegram nicht erreichbar, keine Verbindung" ;;
28) DIREKT_GRUND="Telegram antwortet nicht rechtzeitig" ;;
*) DIREKT_GRUND="curl endete mit Code $rc" ;;
esac
return 1
}
if telegram_direkt; then
# „OK telegram direkt“: services/update_verlauf.py erkennt beide Wege.
echo "$TS OK telegram direkt: $MSG" >> "$LOG"
exit 0
fi
# Letzter Ausweg: Logfile + wall — Meldung darf nie verloren gehen.
GRUND="$SEND_OUT"
[ -n "$DIREKT_GRUND" ] && GRUND="${GRUND:+$GRUND; }Zweitweg: $DIREKT_GRUND"
echo "$TS FALLBACK (telegram fehlgeschlagen: $GRUND): $MSG" >> "$LOG"
if [ "${MC_NOTIFY_OHNE_WALL:-0}" != "1" ]; then
printf '%s\n' "MC2-Meldung: ${SUBJECT:+$SUBJECT }$MSG" | wall 2>/dev/null || true
fi
echo "WARN: Telegram fehlgeschlagen, in $LOG protokolliert" >&2
[ "${MC_NOTIFY_STRICT:-0}" = "1" ] && exit 1
exit 0