Files
klubhaus-doorbell/scripts/monitor-agent.sh

101 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Monitor agent - multiplexed serial monitor for AI interaction
# Usage: ./scripts/monitor-agent.sh <board>
#
# Outputs:
# - /tmp/doorbell-$BOARD.jsonl - JSON Lines log {"ts":123.456,"line":"..."}
# - /tmp/doorbell-$BOARD-state.json - Current device state
# - /tmp/doorbell-$BOARD-cmd.fifo - Command pipe (echo 'cmd' > fifo)
#
# Note: This script should be run after 'mise run kill' to ensure
# any existing processes using the serial port are terminated.
#
# Usage:
# mise run kill BOARD=$BOARD
# ./scripts/monitor-agent.sh $BOARD
# tail -f /tmp/doorbell-$BOARD.jsonl # Watch logs
# echo 'dashboard' > /tmp/doorbell-$BOARD-cmd.fifo # Send command
set -euo pipefail
BOARD="${1:-esp32-32e-4}"
source "./boards/$BOARD/board-config.sh"
SERIAL="$PORT"
LOGFILE="/tmp/doorbell-$BOARD.jsonl"
STATEFILE="/tmp/doorbell-$BOARD-state.json"
CMDFIFO="/tmp/doorbell-$BOARD-cmd.fifo"
SCREENSOCK="doorbell-$BOARD"
# Cleanup
cleanup() {
screen -S "$SCREENSOCK" -X quit 2>/dev/null || true
rm -f "$CMDFIFO"
}
trap cleanup EXIT
# Create command FIFO
rm -f "$CMDFIFO"
mkfifo "$CMDFIFO"
# Initialize state
echo '{"screen":"BOOT","deviceState":"BOOTED","backlightOn":false}' > "$STATEFILE"
# Start screen in detached mode with logging
# -L: enable logging
# -Logfile: specify log file
# -d -m: create detached
# -S: session name
screen -L -Logfile "$LOGFILE.raw" -d -m -S "$SCREENSOCK" "$SERIAL" 115200
# Give screen time to start
sleep 1
# Reader: parse raw screen log -> JSON Lines + state
(
exec >>"$LOGFILE" 2>&1
last_screen_line=""
while IFS= read -r line; do
# Skip duplicate/corrupted lines
[[ "$line" == "$last_screen_line" ]] && continue
last_screen_line="$line"
# Only process non-empty lines
[[ -z "$line" ]] && continue
TS=$(date +%s.%3N)
printf '{"ts":%s,"line":"%s"}\n' "$TS" "$line"
# Parse state changes
case "$line" in
*"[STATE]"*"→ OFF"*) echo '{"screen":"OFF"}' > "$STATEFILE" ;;
*"[STATE]"*"→ DASHBOARD"*) echo '{"screen":"DASHBOARD"}' > "$STATEFILE" ;;
*"[STATE]"*"→ ALERT"*) echo '{"screen":"ALERT"}' > "$STATEFILE" ;;
*"[STATE]"*"→ BOOT"*) echo '{"screen":"BOOT"}' > "$STATEFILE" ;;
*"[ADMIN]"*"dashboard"*) echo '{"screen":"DASHBOARD"}' > "$STATEFILE" ;;
*"[ADMIN]"*"off"*) echo '{"screen":"OFF"}' > "$STATEFILE" ;;
esac
done < "$LOGFILE.raw"
) &
READER_PID=$!
# Writer: command FIFO -> screen session
(
while IFS= read -r cmd < "$CMDFIFO"; do
# Send command to screen session
screen -S "$SCREENSOCK" -X stuff "$cmd^M"
echo "[SENT] $cmd"
done
) &
WRITER_PID=$!
echo "Monitor agent started (BOARD=$BOARD):"
echo " Log: $LOGFILE"
echo " State: $STATEFILE"
echo " Cmd: echo 'dashboard' > $CMDFIFO"
echo ""
echo "Press Ctrl+C to exit"
# Wait for reader
wait "$READER_PID" || true