generated from me/template-mit
Compare commits
15
Commits
main
..
35db6c2c5f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35db6c2c5f | ||
|
|
f671e3d94d | ||
|
|
68b703ff7e | ||
|
|
21f02945bb | ||
|
|
fae03c94d9 | ||
|
|
ffc29eabb2 | ||
|
|
b14e6a3660 | ||
|
|
9e294d070f | ||
|
|
68ae3e1b9a | ||
|
|
3a36ec9651 | ||
|
|
eb0555fd77 | ||
|
|
f145f7122e | ||
|
|
0713442b78 | ||
|
|
6ce4a9bbf0 | ||
|
|
15c909d954 |
No files matched your search
@@ -1,3 +1,105 @@
|
||||
# template-mit
|
||||
# Sunset Alarm (CLI)
|
||||
|
||||
Template with MIT license, protected `main` branch, and available `dev` branch.
|
||||
Simple command line shell script which can be run as a user daemon for alerts.
|
||||
|
||||
## Description
|
||||
|
||||
Sunset Alarm allows a user to receive an alert at a specified amount of minutes
|
||||
before sunset. This may be helpful for starting any practices such as preparing
|
||||
for sungazing, or as a reminder to go and find a campsite before it gets dark.
|
||||
|
||||
## Usage
|
||||
|
||||
`()` sections are required.
|
||||
`[]` sections are optional.
|
||||
`|` separates multiple options in a group.
|
||||
|
||||
```console
|
||||
sunset-timer (-l LAT:LONG | -t HH24:MI) (-m MINUTES) [-h]
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Set an alarm 90 minutes before for your lat/long experiences sunset:
|
||||
|
||||
```shell
|
||||
sunset-alarm -l 32.123:-111.111 -m 90
|
||||
```
|
||||
|
||||
Set an alarm 5 minutes after a manually determined sunset time:
|
||||
|
||||
```shell
|
||||
sunset-alarm -t 18:00 -m -5
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
Recommended installation location is under `/usr/local/*`.
|
||||
|
||||
```console
|
||||
# git clone http://git.hyperling.com/me/sunset-alarm-cli /usr/local/src/sunset_alarm_cli
|
||||
# ln -s /usr/local/src/sunset_alarm_cli/sunset-alarm /usr/local/bin/
|
||||
```
|
||||
|
||||
### Daemonize
|
||||
|
||||
**runit**
|
||||
|
||||
Create the run file:
|
||||
|
||||
```console
|
||||
# vi /etc/sv/sunset-alarm/run:
|
||||
```
|
||||
|
||||
```shell
|
||||
#!/bin/sh -e
|
||||
exec 2>&1
|
||||
chpst -u user /usr/local/bin/sunset-alarm -l 33:-112 -m 15
|
||||
```
|
||||
|
||||
Enable the service:
|
||||
|
||||
```console
|
||||
# ln -s /etc/sv/sunset-alarm /var/services/
|
||||
```
|
||||
|
||||
### i3
|
||||
|
||||
Simply add an exec to the end of your config file.
|
||||
|
||||
```shell
|
||||
echo "exec --no-startup-id /usr/local/bin/sunset-alarm -l 33:-112 -m 15" >> ~/.config/i3/config
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
### Required
|
||||
|
||||
-m : Accepts a minute value which is used to check if we have approached the
|
||||
alert period before sunset. Can be positive, negative, or 0.
|
||||
|
||||
### Optional
|
||||
|
||||
-l : Accepts a lat:long value which is used to check Open Meteo for the
|
||||
location's sunset time. This is required if -t is not passed.
|
||||
|
||||
-t : Accepts a time value for sunset time. If this is passed, it bypasses the
|
||||
Open Meteo check and acts as a hardcoded time. The minutes parameter is still
|
||||
required to know when to alert prior to this time.
|
||||
|
||||
## Design
|
||||
|
||||
App displays a persistent alert via `fyi` with fallbacks of `notify-send`,
|
||||
`wall`, and others. Appears once when current time is between (sunset - minutes)
|
||||
and midnight. Even if the system is powered on after the alert time has passed,
|
||||
the program continues displaying the alert repeatedly until the day has passed.
|
||||
|
||||
App requires an internet connection. If no connection is found, it sleeps for 5
|
||||
minutes and then tries again to retrieve the sunset time. Once the sunset time
|
||||
has been retrieved for the day, it stops checking Open Meteo until the next day.
|
||||
|
||||
App is short, sweet, concise, and succinct without using any odd syntax or line
|
||||
combining to achieve this. Does not pull in any extraneous libraries, only uses
|
||||
utilities which are already installed on the system. Program is coded to use a
|
||||
range of utilities in case the primary choices are not available. If no choices
|
||||
are installed, displays an ERROR message with a list of software to download.
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
#!/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://hyperling,com; then
|
||||
return 0
|
||||
fi
|
||||
if curl -s --max-time 5 -o /dev/null https://mullvad.net; 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 at $(date -d @${SUNSET_EPOCH} +"%H:%M")."
|
||||
|
||||
persistent="-t 0 --wait"
|
||||
icon="-i weather-clear -u critical"
|
||||
|
||||
if command -v fyi >/dev/null 2>&1; then
|
||||
fyi $icon $persistent "$TITLE" "$MESSAGE"
|
||||
elif command -v notify-send >/dev/null 2>&1; then
|
||||
notify-send $icon $persistent "$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) ))
|
||||
|
||||
# Calculate midnight of the current day
|
||||
MIDNIGHT=$(date -d "${TODAY} +1 day" +%s)
|
||||
|
||||
# Alert while current time is within the window (from window start until midnight)
|
||||
if [ "$CURRENT_TIME" -ge "$ALERT_WINDOW_START" ] && \
|
||||
[ "$CURRENT_TIME" -lt "$MIDNIGHT" ]; then
|
||||
show_alert
|
||||
sleep 5 # Re-alert every 5 minutes while in alert window
|
||||
else
|
||||
sleep 60
|
||||
fi
|
||||
|
||||
# Reset when we've passed midnight so we fetch new time tomorrow
|
||||
if [ "$CURRENT_TIME" -ge "$MIDNIGHT" ]; then
|
||||
LAST_DATE=""
|
||||
fi
|
||||
done
|
||||
Reference in new issue
Block a user