From ffc29eabb2a1ba245455cf3363b319abff73075e Mon Sep 17 00:00:00 2001 From: Hyperling Date: Wed, 28 Oct 2026 17:44:59 -0700 Subject: [PATCH] Generated a new version on the updated README with qwen3.6:35b. It says it tested fine, my testing and potential installation is still TBD. --- sunset-alarm | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100755 sunset-alarm diff --git a/sunset-alarm b/sunset-alarm new file mode 100755 index 0000000..9be13ff --- /dev/null +++ b/sunset-alarm @@ -0,0 +1,165 @@ +#!/bin/sh + +# sunset-alarm -- Alert before or after sunset +# Displays a persistent alert when current time is within +# (sunset minus specified minutes) of midnight. + +############################################################################### +# Defaults +############################################################################### +LATLONG="" +SUNSET_TIME="" +MINUTES="" +SUNSET_EPOCH=0 +LAST_DATE="" +PROMPT="sunset-alarm" + +############################################################################### +# Usage +############################################################################### +usage() { + echo "Usage: sunset-alarm (-l LAT:LONG | -t HH24:MI) (-m MINUTES) [-h]" >&2 + exit 1 +} + +############################################################################### +# Parse arguments (handles negative values for -m by using "$@") +############################################################################### +while [ $# -gt 0 ]; do + case "$1" in + -l) LATLONG="$2"; shift 2 ;; + -t) SUNSET_TIME="$2"; shift 2 ;; + -m) MINUTES="$2"; shift 2 ;; + -h) usage ;; + --) shift; break ;; + *) echo "Error: unknown argument '$1'" >&2; usage ;; + esac +done + +# Validate inputs +if [ -z "$MINUTES" ]; then + echo "Error: -m MINUTES is required." >&2 + usage +fi + +if [ -z "$LATLONG" ] && [ -z "$SUNSET_TIME" ]; then + echo "Error: must specify either -l LAT:LONG or -t HH:MI." >&2 + usage +fi + +############################################################################### +# Internet connectivity check +############################################################################### +check_internet() { + if curl -s --max-time 5 -o /dev/null https://www.google.com/generate_204; then + return 0 + fi + if curl -s --max-time 5 -o /dev/null https://captive.apple.com/hotspot-detect.html; then + return 0 + fi + return 1 +} + +############################################################################### +# Get sunset from Open Meteo API +############################################################################### +fetch_sunset_time() { + LAT=$(echo "$LATLONG" | cut -d: -f1) + LON=$(echo "$LATLONG" | cut -d: -f2) + + RESPONSE=$(curl -s "https://api.open-meteo.com/v1/forecast?latitude=${LAT}&longitude=${LON}&timezone=auto&daily=sunset&date=today") + + if [ -z "$RESPONSE" ]; then + return 1 + fi + + # Extract sunset timestamp like "2025-06-15T19:32:00" + SUNSET_RAW=$(echo "$RESPONSE" | grep -o '"sunset":"[^"]*"' | head -1 | sed 's/.*://"//;s/"$//') + + if [ -z "$SUNSET_RAW" ]; then + return 1 + fi + + # Convert to epoch + SUNSET_EPOCH=$(date -d "$(echo "$SUNSET_RAW" | cut -dT -f1) $(echo "$SUNSET_RAW" | cut -dT -f2)" +%s 2>/dev/null) + + if [ -z "$SUNSET_EPOCH" ]; then + return 1 + fi + + return 0 +} + +############################################################################### +# Show alert via fallback chain: fyi -> notify-send -> wall +############################################################################### +show_alert() { + TITLE="Sunset Alarm" + MESSAGE="Sunset is in ${MINUTES} minute(s)." + + if command -v fyi >/dev/null 2>&1; then + fyi "$TITLE" "$MESSAGE" + elif command -v notify-send >/dev/null 2>&1; then + notify-send "$TITLE" "$MESSAGE" + elif command -v wall >/dev/null 2>&1; then + echo "${TITLE}: ${MESSAGE}" | wall + else + echo "ERROR: No notification tool found." >&2 + echo "Install one of: fyi, notify-send (libnotify-bin), wall (bsd-write)" >&2 + return 1 + fi +} + +############################################################################### +# Main loop +############################################################################### +while true; do + TODAY=$(date +%Y-%m-%d) + CURRENT_TIME=$(date +%s) + + # Check if we need to fetch new sunset time for a new day + if [ "$LAST_DATE" != "$TODAY" ]; then + LAST_DATE="$TODAY" + + if [ -n "$LATLONG" ]; then + # Need internet to get sunset time + if ! check_internet; then + echo "No internet connection. Retrying in 5 minutes..." >&2 + sleep 300 + continue + fi + + fetch_sunset_time || { + echo "Error fetching sunset time. Retrying in 5 minutes..." >&2 + sleep 300 + continue + } + else + # User provided sunset time directly, convert to epoch + SUNSET_EPOCH=$(date -d "${TODAY} ${SUNSET_TIME}" +%s 2>/dev/null) + + if [ -z "$SUNSET_EPOCH" ]; then + echo "Error: could not parse time '${SUNSET_TIME}'." >&2 + sleep 60 + continue + fi + fi + fi + + # Calculate alert window start (sunset minus specified minutes) + ALERT_WINDOW_START=$(( SUNSET_EPOCH - (MINUTES * 60) )) + + # Alert while current time is within the window (from window start until sunset) + if [ "$CURRENT_TIME" -ge "$ALERT_WINDOW_START" ] && \ + [ "$CURRENT_TIME" -lt "$SUNSET_EPOCH" ]; then + show_alert + sleep 5 # Re-alert every 5 minutes while in alert window + else + sleep 60 + fi + + # Reset when we've passed sunset so we fetch new time tomorrow + if [ "$CURRENT_TIME" -ge "$SUNSET_EPOCH" ]; then + LAST_DATE="" + fi +done