Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e1cb8857d | ||
|
|
63bbe5c2ab |
@@ -65,14 +65,16 @@ if ! $TEST_MODE; then
|
||||
start_sec=$((sunrise_sec - SUNRISE_PRE_MIN * 60))
|
||||
end_sec=$((sunrise_sec + SUNRISE_POST_MIN * 60))
|
||||
echo "Window: $((start_sec/3600)):$(printf '%02d' $(((start_sec%3600)/60))) → $((end_sec/3600)):$(printf '%02d' $(((end_sec%3600)/60)))"
|
||||
midnight=$(date -d "today 00:00:00" +%s)
|
||||
now_day_sec=$(( $(date +%s) - midnight ))
|
||||
if [ "$now_day_sec" -lt "$end_sec" ]; then
|
||||
wait_sec=$(( end_sec - now_day_sec + 30 ))
|
||||
echo "Waiting ${wait_sec}s for capture window to finish (ends $(date -d "@$(( midnight + end_sec ))" '+%H:%M:%S'))..."
|
||||
# Resolve wall-clock targets through `date -d` instead of adding seconds-since-
|
||||
# midnight to a midnight epoch: on a DST day (23h/25h) the two differ by 3600s.
|
||||
end_epoch=$(date -d "today $(printf '%02d:%02d:%02d' $((end_sec/3600)) $(((end_sec%3600)/60)) $((end_sec%60)))" +%s)
|
||||
now_epoch=$(date +%s)
|
||||
if [ "$now_epoch" -lt "$end_epoch" ]; then
|
||||
wait_sec=$(( end_epoch - now_epoch + 30 ))
|
||||
echo "Waiting ${wait_sec}s for capture window to finish (ends $(date -d "@$end_epoch" '+%H:%M:%S'))..."
|
||||
sleep "$wait_sec"
|
||||
else
|
||||
echo "Capture window already closed at $(date -d "@$(( midnight + end_sec ))" '+%H:%M:%S') — processing available images"
|
||||
echo "Capture window already closed at $(date -d "@$end_epoch" '+%H:%M:%S') — processing available images"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+19
@@ -296,6 +296,25 @@ for cam in "${CAMERAS[@]}"; do
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Timezone drift check ─────────────────────────────────────────────────────
|
||||
# Daily + shortly after boot: notify if TIMEZONE no longer matches the
|
||||
# machine's timezone (systemd timers follow the machine, scripts follow TIMEZONE).
|
||||
write_service "sky-cam-tzcheck" "timezone drift check" "tz-drift-check.sh"
|
||||
cat > "$UNIT_DIR/sky-cam-tzcheck.timer" <<EOF2
|
||||
[Unit]
|
||||
Description=Sky-Cam — timezone drift check
|
||||
|
||||
[Timer]
|
||||
OnBootSec=3min
|
||||
OnCalendar=*-*-* 12:00:00
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF2
|
||||
echo " wrote sky-cam-tzcheck.timer"
|
||||
timers+=("sky-cam-tzcheck")
|
||||
|
||||
# ── Generate .env.example ────────────────────────────────────────────────────
|
||||
env_example="$HERE/.env.example"
|
||||
{
|
||||
|
||||
@@ -54,12 +54,13 @@ record_dur_sec=$SUNRISE_TARGET_SECS
|
||||
|
||||
echo "Audio window: ${half_pre}s before → ${half_post}s after sunrise (${record_dur_sec}s total)"
|
||||
|
||||
midnight=$(date -d "today 00:00:00" +%s)
|
||||
now_day_sec=$(( $(date +%s) - midnight ))
|
||||
wait_sec=$(( record_start_sec - now_day_sec ))
|
||||
# Resolve the wall-clock start via `date -d` (not midnight epoch + seconds):
|
||||
# on a DST day (23h/25h) those differ by 3600s.
|
||||
start_epoch=$(date -d "today $(printf '%02d:%02d:%02d' $((record_start_sec/3600)) $(((record_start_sec%3600)/60)) $((record_start_sec%60)))" +%s)
|
||||
wait_sec=$(( start_epoch - $(date +%s) ))
|
||||
|
||||
if [ "$wait_sec" -gt 0 ]; then
|
||||
echo "Waiting ${wait_sec}s until audio window ($(date -d "@$(( midnight + record_start_sec ))" '+%H:%M:%S'))..."
|
||||
echo "Waiting ${wait_sec}s until audio window ($(date -d "@$start_epoch" '+%H:%M:%S'))..."
|
||||
sleep "$wait_sec"
|
||||
fi
|
||||
|
||||
|
||||
+3
-1
@@ -58,7 +58,9 @@ tz = pytz.timezone(conf['TIMEZONE'])
|
||||
# This bracket is timezone-correct and handles any UTC offset, including large
|
||||
# positive offsets (UTC+12/+14) where local midnight falls on the previous UTC day.
|
||||
now_local = datetime.now(tz)
|
||||
midnight_local = now_local.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
# tz.localize (not .replace) so the UTC offset is re-resolved for midnight —
|
||||
# on a DST-change day now_local's offset differs from midnight's.
|
||||
midnight_local = tz.localize(datetime(now_local.year, now_local.month, now_local.day))
|
||||
t0_utc = midnight_local.astimezone(timezone.utc)
|
||||
t1_utc = t0_utc + timedelta(hours=25) # 25 h covers any timezone's full day
|
||||
|
||||
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
# tz-drift-check.sh — warn if TIMEZONE (sky-cam.conf / .env) no longer matches
|
||||
# the machine's own timezone.
|
||||
#
|
||||
# systemd timers fire on the machine's clock, but sunrise.py, the capture
|
||||
# scripts and the per-day folder names use TIMEZONE. If the two drift apart
|
||||
# (someone ran `timedatectl set-timezone`, a cloud-init reset, a restored
|
||||
# image, a typo in .env...) every scheduled job runs at the wrong local time
|
||||
# and the sunrise capture window is off by the zone difference.
|
||||
#
|
||||
# Run daily by sky-cam-tzcheck.timer (and shortly after boot). Sends one
|
||||
# notify.sh message per run while the mismatch persists; silent when fine.
|
||||
# Exit 0 either way — a mismatch is a notification, not a job failure.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
source "$SCRIPT_DIR/sky-cam.conf"
|
||||
source "$SCRIPT_DIR/.env" 2>/dev/null || true
|
||||
|
||||
# Machine's zone — read WITHOUT any TZ override so we see the real system value.
|
||||
sys_tz="$(env -u TZ timedatectl show -p Timezone --value 2>/dev/null)"
|
||||
[ -z "$sys_tz" ] && sys_tz="$(cat /etc/timezone 2>/dev/null)"
|
||||
[ -z "$sys_tz" ] && sys_tz="$(readlink /etc/localtime 2>/dev/null | sed 's|.*/zoneinfo/||')"
|
||||
if [ -z "$sys_tz" ]; then
|
||||
echo "tz-drift-check: could not determine the machine's timezone — skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Compare by real UTC offsets across the year so aliases (US/Eastern vs
|
||||
# America/New_York) and identical-rule zones are not reported as drift.
|
||||
same=true
|
||||
if [ "$sys_tz" != "$TIMEZONE" ]; then
|
||||
for m in 01 04 07 10; do
|
||||
a="$(TZ="$sys_tz" date -d "2026-$m-15 12:00 UTC" +%z)"
|
||||
b="$(TZ="$TIMEZONE" date -d "2026-$m-15 12:00 UTC" +%z)"
|
||||
[ "$a" = "$b" ] || { same=false; break; }
|
||||
done
|
||||
fi
|
||||
|
||||
if $same; then
|
||||
echo "Timezone OK: sky-cam TIMEZONE=$TIMEZONE, machine=$sys_tz"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg="sky-cam TIMEZONE is $TIMEZONE but this machine's timezone is $sys_tz. Scheduled jobs run on the machine clock, so sunrise/seasons/moon jobs will fire at the wrong local time. Fix: set TIMEZONE=$sys_tz in $SCRIPT_DIR/.env and re-run ./install.sh, or run: sudo timedatectl set-timezone $TIMEZONE"
|
||||
echo "WARNING: $msg"
|
||||
"$SCRIPT_DIR/notify.sh" "WARNING: sky-cam timezone mismatch" "$msg" || true
|
||||
exit 0
|
||||
Reference in New Issue
Block a user