Files
openclaw-ops/skills/capmetro-monitor/scripts/watch-departure.sh

104 lines
4.5 KiB
Bash
Executable File

#!/bin/bash
# Route 5 departure watcher — runs in background, posts to Discord when bus departs
# Usage: bash watch-departure.sh <scheduled_time_UTC> [channel_id]
# Example: bash watch-departure.sh "2026-02-12T13:30:00Z" 1467247377743347953
set -eo pipefail
SCHED_DEPART="$1"
CHANNEL="${2:-1467247377743347953}" # Default: DM channel
VP_URL="https://data.texas.gov/download/cuc7-ywmd/application%2Fjson"
FIRST_STOP="5854"
USER_STOP="964"
TOKEN=$(printenv DISCORD_BOT_TOKEN)
MAX_POLLS=40 # ~13 minutes max watch time
POLL_INTERVAL=20 # seconds between polls
# Find the trip matching this scheduled departure
find_trip() {
local TU=$(curl -sL --max-time 10 "https://data.texas.gov/download/mqtr-wwpy/application%2Fjson" 2>/dev/null)
echo "$TU" | jq -r --arg sched "$SCHED_DEPART" '.entity[] |
select(.tripUpdate.trip.routeId == "5" and .tripUpdate.trip.directionId == 0) |
select([.tripUpdate.stopTimeUpdate[] | select(.stopId == "5854") |
((.departure.time // .arrival.time) | tonumber)] | .[0] == ($sched | sub("Z$";"") | strptime("%Y-%m-%dT%H:%M:%S") | mktime)) |
.tripUpdate.trip.tripId' 2>/dev/null | head -1
}
# Convert ISO to epoch
sched_epoch() {
date -d "$SCHED_DEPART" +%s 2>/dev/null || date -u -d "${SCHED_DEPART%Z}" +%s 2>/dev/null
}
SCHED_TS=$(sched_epoch)
SCHED_CST=$(TZ=America/Chicago date -d "@$SCHED_TS" +"%I:%M %p" 2>/dev/null)
# Find the trip ID
TRIP_ID=$(find_trip)
if [ -z "$TRIP_ID" ]; then
# Fallback: find closest eastbound trip
TU=$(curl -sL --max-time 10 "https://data.texas.gov/download/mqtr-wwpy/application%2Fjson" 2>/dev/null)
TRIP_ID=$(echo "$TU" | jq -r --arg ts "$SCHED_TS" '[.entity[] |
select(.tripUpdate.trip.routeId == "5" and .tripUpdate.trip.directionId == 0) |
{tripId: .tripUpdate.trip.tripId, depart: ([.tripUpdate.stopTimeUpdate[] | select(.stopId == "5854") | (.departure.time // .arrival.time)] | .[0] | tonumber)}] |
sort_by((. .depart - ($ts | tonumber)) | fabs) | .[0].tripId' 2>/dev/null)
fi
if [ -z "$TRIP_ID" ]; then
# Post error
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
-d "{\"content\":\"⚠️ Could not find Route 5 trip for $SCHED_CST departure.\"}" \
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null
exit 1
fi
# Poll until departure
for i in $(seq 1 $MAX_POLLS); do
VP=$(curl -sL --max-time 8 "https://data.texas.gov/download/cuc7-ywmd/application%2Fjson" 2>/dev/null)
VEHICLE=$(echo "$VP" | jq -c ".entity[] | select(.vehicle.trip.tripId == \"$TRIP_ID\")" 2>/dev/null)
if [ -z "$VEHICLE" ]; then
sleep $POLL_INTERVAL
continue
fi
STOP_ID=$(echo "$VEHICLE" | jq -r '.vehicle.stopId')
STATUS=$(echo "$VEHICLE" | jq -r '.vehicle.currentStatus')
SPEED=$(echo "$VEHICLE" | jq -r '.vehicle.position.speed')
VEH_ID=$(echo "$VEHICLE" | jq -r '.vehicle.vehicle.label')
# Bus has left the first stop
if [ "$STOP_ID" != "$FIRST_STOP" ] || ([ "$STATUS" = "IN_TRANSIT_TO" ] && [ "$STOP_ID" != "$FIRST_STOP" ]); then
DEPART_TS=$(date +%s)
DEPART_CST=$(TZ=America/Chicago date +"%I:%M:%S %p")
DELAY=$((DEPART_TS - SCHED_TS))
DELAY_MIN=$((DELAY / 60))
# Calculate ETA at user stop (7m26s from first stop)
ETA_TS=$((DEPART_TS + 446))
ETA_CST=$(TZ=America/Chicago date -d "@$ETA_TS" +"%I:%M %p" 2>/dev/null)
if [ "$DELAY_MIN" -le 0 ]; then
STATUS_MSG="🟢 On time"
elif [ "$DELAY_MIN" -le 2 ]; then
STATUS_MSG="🟡 ~${DELAY_MIN}min late"
else
STATUS_MSG="🔴 ${DELAY_MIN}min late"
fi
MSG="🚌 **Route 5 Departed!**\nBus ${VEH_ID} left Anderson/Northcross at ${DEPART_CST}\nScheduled: ${SCHED_CST} | ${STATUS_MSG}\n📍 ETA at Woodrow/Choquette: **${ETA_CST}**"
CONTENT=$(printf "$MSG")
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
-d "$(jq -n --arg c "$CONTENT" '{content: $c}')" \
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null
exit 0
fi
sleep $POLL_INTERVAL
done
# Timeout — bus never departed (or we missed it)
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
-d "{\"content\":\"⚠️ Route 5 watcher timed out — could not confirm $SCHED_CST departure from Anderson/Northcross.\"}" \
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null