Merge pull request #73 from outis1one/claude/fix-sunrise-video-timing-hKgfU

sunrise.py: replace suntime with skyfield for accurate sunrise calcul…
This commit is contained in:
Outis
2026-05-13 23:25:03 -04:00
committed by GitHub
4 changed files with 55 additions and 11 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ echo "Processing: $yesterday"
# ── Season / movement info from astronomical calculation ──────────────────────
_season_info="$(python3 "$SCRIPT_DIR/season_info.py" "$yesterday")" || {
echo "Error: season_info.py failed — check Python dependencies (suntime pytz)"
echo "Error: season_info.py failed — check Python dependencies (pytz)"
exit 1
}
eval "$_season_info"
+2 -2
View File
@@ -22,8 +22,8 @@ echo ""
echo "Done. Next steps:"
echo " 1. Install system packages (if not already present):"
echo " sudo apt install ffmpeg bc fonts-dejavu"
echo " pip3 install suntime pytz requests"
echo " pip3 install skyfield Pillow numpy scipy # moon jobs (moon-track, moon-phase-monthly)"
echo " pip3 install pytz requests skyfield"
echo " pip3 install Pillow numpy scipy # moon jobs (moon-track, moon-phase-monthly)"
echo ""
echo " 2. Edit $TARGET/sky-cam.conf"
echo " — SCRIPT_DIR full path to the directory you'll run scripts from"
+1 -1
View File
@@ -47,7 +47,7 @@ ATTR_FADE="$MONTAGE_ATTR_FADE"
# ── Season / movement info ────────────────────────────────────────────────────
_season_info="$(python3 "$SCRIPT_DIR/season_info.py" ${DATE_ARG:+"$DATE_ARG"})" || {
echo "Error: season_info.py failed — check Python dependencies (suntime pytz)"
echo "Error: season_info.py failed — check Python dependencies (pytz)"
exit 1
}
eval "$_season_info"
+51 -7
View File
@@ -1,13 +1,24 @@
#!/usr/bin/env python3
from datetime import datetime
"""sunrise.py — compute today's local sunrise time using skyfield.
Outputs: YYYY-MM-DD HH:MM:SS (local time, no timezone suffix)
Exits non-zero with a message on stderr if the sun does not rise today
(polar night or midnight sun).
Reads LATITUDE, LONGITUDE, TIMEZONE from sky-cam.conf / .env.
Requires skyfield and the de421.bsp ephemeris alongside this script
(skyfield downloads de421.bsp automatically on first use if absent).
"""
from datetime import datetime, timezone, timedelta
import pathlib
import re
import pytz
from suntime import Sun
_here = pathlib.Path(__file__).resolve().parent
def _read_conf(path):
conf = {}
try:
@@ -30,6 +41,7 @@ def _read_conf(path):
pass
return conf
conf = _read_conf(_here / 'sky-cam.conf')
# .env overrides sky-cam.conf — mirrors the sourcing order at the bottom of sky-cam.conf
conf.update(_read_conf(_here / '.env'))
@@ -42,9 +54,41 @@ latitude = float(conf['LATITUDE'])
longitude = float(conf['LONGITUDE'])
tz = pytz.timezone(conf['TIMEZONE'])
sun = Sun(latitude, longitude)
now = datetime.now(tz)
sunrise_utc = sun.get_sunrise_time(now)
sunrise_time = sunrise_utc.astimezone(tz)
# Search the full local calendar day (midnight→midnight) expressed in UTC.
# 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)
t0_utc = midnight_local.astimezone(timezone.utc)
t1_utc = t0_utc + timedelta(hours=25) # 25 h covers any timezone's full day
print(sunrise_time.strftime('%Y-%m-%d %H:%M:%S'))
from skyfield.api import Loader, wgs84
from skyfield.almanac import find_discrete, sunrise_sunset
loader = Loader(str(_here), verbose=False)
ts = loader.timescale()
eph = loader('de421.bsp') # downloaded automatically on first run
topos = wgs84.latlon(latitude, longitude)
t0 = ts.from_datetime(t0_utc)
t1 = ts.from_datetime(t1_utc)
times, events = find_discrete(t0, t1, sunrise_sunset(eph, topos))
# events: True = sunrise, False = sunset — pick the first sunrise on today's date
sunrise_local = None
for t, is_rise in zip(times, events):
if is_rise:
candidate = t.utc_datetime().astimezone(tz)
if candidate.date() == now_local.date():
sunrise_local = candidate
break
if sunrise_local is None:
raise SystemExit(
"sunrise.py: no sunrise found for today "
f"({now_local.date()} at {latitude:.4f}°, {longitude:.4f}°) — "
"polar night or midnight sun?"
)
print(sunrise_local.strftime('%Y-%m-%d %H:%M:%S'))