Files
Linux_post_install/bin/pos-system-event-trigger
T
Your Name 5f2c8fdcec feat: event-trigger run logs live value on no-change
Diagnosis aid: when a rule evaluates but doesn't fire, run now prints
'OK: <cmd> = <value> (no change)' so a rule that silently never crosses
its threshold (e.g. wrong sensor in the check command) is visible
instead of just 'evaluated N rule(s)'.
2026-08-09 18:11:51 +00:00

220 lines
8.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# POS: system event-trigger — State-based rule monitors; alerts via notify when a check crosses a threshold
# POS_SUBCMDS: run config list enable disable status
# POS_FLAGS: --dry-run
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
source "$(dirname "$0")/../lib/eventer-lib.sh" 2>/dev/null || source "$(dirname "$0")/eventer-lib.sh"
source "$(dirname "$0")/../lib/notify.sh" 2>/dev/null || source "$(dirname "$0")/notify.sh"
usage() {
cat <<EOF
Usage: pos system event-trigger <subcommand> [--dry-run]
State-based rule monitors. Each line in event.env is an independent rule:
"<message>" if <check-command> <op> <threshold>
<check-command> <op> <threshold>
The check command is run on every pass; when its first numeric output
crosses the threshold the message is sent via lib/notify.sh (Telegram by
default). Rules fire on false→true only, plus one recovery message.
Subcommands:
run Evaluate every rule once (the systemd timer calls this)
config Interactive editor: add / remove <n> / edit <n> / quit
list Show rules with their live check values
enable [interval] Install + start the user timer (default 5m; also:
10m 15m 30m 45m hourly 2h 6h 12h daily weekly, OnCalendar=…)
disable Stop + remove the timer
status Timer + rule count
Options:
--dry-run Preview what would fire / be written, without sending
-h, --help This help
Rules file: $CONFIG_FILE (chmod 600)
Examples:
pos system event-trigger list
pos system event-trigger config
pos system event-trigger enable 5m
pos system event-trigger run --dry-run
EOF
exit 0
}
case "${1:-}" in
-h|--help|"") usage ;;
esac
DRY_RUN=0
args=()
for a in "$@"; do
case "$a" in
--dry-run) DRY_RUN=1 ;;
*) args+=("$a") ;;
esac
done
set -- "${args[@]}"
[ -f "$CONFIG_FILE" ] || { log "no rules file yet — run 'pos system event-trigger config'"; }
# ── run ──────────────────────────────────────────────────────────
run_rules() {
eventer_read_rules
local n fired hash msg line skipped
n=0
skipped=0
for line in "${RULES[@]}"; do
case "$line" in
""|\#*) continue ;;
esac
eventer_parse_rule "$line" || { warn "skipping unparseable rule: $line"; skipped=$((skipped + 1)); continue; }
eventer_eval_check || { warn "check produced no number — $RULE_CMD"; skipped=$((skipped + 1)); continue; }
n=$((n + 1))
if eventer_compare "$VALUE_NUM" "$RULE_OP" "$RULE_NUM"; then fired=1; else fired=0; fi
hash="$(eventer_hash "$line")"
if [ "$fired" -eq 1 ] && ! eventer_state_is_firing "$hash"; then
msg="$(eventer_alert_msg)"
if [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) TRIGGER: $msg"
else
notify_send "$msg"
eventer_state_set "$hash" 1
fi
elif [ "$fired" -eq 0 ] && eventer_state_is_firing "$hash"; then
msg="$(eventer_recover_msg)"
if [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) RECOVER: $msg"
else
notify_send "$msg"
eventer_state_set "$hash" 0
fi
elif [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) OK: $RULE_CMD = $VALUE_DISPLAY (no change)"
else
log "OK: $RULE_CMD = $VALUE_DISPLAY (no change)"
fi
done
if [ "$skipped" -gt 0 ]; then
log "evaluated $n rule(s), skipped $skipped (no number / unparseable)"
else
log "evaluated $n rule(s)"
fi
}
# ── list ─────────────────────────────────────────────────────────
list_rules() {
eventer_read_rules
local i=0 line
for line in "${RULES[@]}"; do
i=$((i + 1))
case "$line" in
""|\#*) printf '%2d (comment/blank)\n' "$i"; continue ;;
esac
if eventer_parse_rule "$line"; then
if eventer_eval_check; then
printf '%2d [%s %s %s] %s = %s\n' "$i" "$RULE_CMD" "$RULE_OP" "$RULE_THRESH" \
"${RULE_MSG:+msg: $RULE_MSG; }" "$VALUE_DISPLAY"
else
printf '%2d [%s %s %s] (check produced no number)\n' "$i" "$RULE_CMD" "$RULE_OP" "$RULE_THRESH"
fi
else
printf '%2d INVALID — %s\n' "$i" "$line"
fi
done
[ "$i" -gt 0 ] || echo "(no rules — run 'pos system event-trigger config')"
}
# ── config editor ────────────────────────────────────────────────
config_editor() {
eventer_read_rules
local n rule action ok
while true; do
echo "── rules in $CONFIG_FILE ──" >&2
if [ "${#RULES[@]}" -eq 0 ]; then
echo " (empty)" >&2
else
for i in "${!RULES[@]}"; do
printf ' %2d %s\n' "$((i + 1))" "${RULES[i]}" >&2
done
fi
read -rp "action [add / remove <n> / edit <n> / quit]: " action
case "$action" in
quit|q) break ;;
add)
read -rp "Rule (\"msg\" if <cmd> <op> <thr>): " rule
[ -n "$rule" ] || continue
if ! eventer_parse_rule "$rule"; then
warn "not a valid rule — need: <command> <op> <threshold> (op: > < >= <= == !=)"
continue
fi
if ! eventer_eval_check; then
warn "check '$RULE_CMD' produced no number — rule added anyway (it will warn on run)"
else
ok "check '$RULE_CMD' currently reports $VALUE_DISPLAY"
fi
if grep -Fxq "$rule" "$CONFIG_FILE" 2>/dev/null; then
warn "rule already present, not added"
elif [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) would add: $rule"
else
mkdir -p "$(dirname "$CONFIG_FILE")"
printf '%s\n' "$rule" >>"$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
eventer_read_rules
fi
;;
remove*)
n="${action#remove }"
[[ "$n" =~ ^[0-9]+$ ]] || { warn "use: remove <line-number>"; continue; }
if [ "$n" -lt 1 ] || [ "$n" -gt "${#RULES[@]}" ]; then
warn "no line $n"; continue
fi
read -rp "remove line $n: '${RULES[$((n - 1))]}'? [y/N]: " ok
[[ "$ok" =~ ^[Yy] ]] || continue
if [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) would remove line $n"
else
unset "RULES[$((n - 1))]"
RULES=("${RULES[@]}")
eventer_write_rules
fi
;;
edit*)
n="${action#edit }"
[[ "$n" =~ ^[0-9]+$ ]] || { warn "use: edit <line-number>"; continue; }
if [ "$n" -lt 1 ] || [ "$n" -gt "${#RULES[@]}" ]; then
warn "no line $n"; continue
fi
printf ' current: %s\n' "${RULES[$((n - 1))]}" >&2
read -rp " new rule (blank = keep): " rule
[ -n "$rule" ] || continue
if ! eventer_parse_rule "$rule"; then
warn "not a valid rule — edit cancelled"
continue
fi
if [ "$DRY_RUN" -eq 1 ]; then
log "(dry-run) would replace line $n"
else
RULES[$((n - 1))]="$rule"
eventer_write_rules
fi
;;
*) warn "unknown action (add | remove <n> | edit <n> | quit)" ;;
esac
done
}
case "${1:-}" in
run) run_rules ;;
config) config_editor ;;
list) list_rules ;;
enable) eventer_enable "${2:-5m}" ;;
disable) eventer_disable ;;
status) eventer_status ;;
*) err "unknown subcommand '${1:-}' (see --help)" ;;
esac