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:
+1
-1
@@ -39,7 +39,7 @@ echo "Processing: $yesterday"
|
|||||||
|
|
||||||
# ── Season / movement info from astronomical calculation ──────────────────────
|
# ── Season / movement info from astronomical calculation ──────────────────────
|
||||||
_season_info="$(python3 "$SCRIPT_DIR/season_info.py" "$yesterday")" || {
|
_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
|
exit 1
|
||||||
}
|
}
|
||||||
eval "$_season_info"
|
eval "$_season_info"
|
||||||
|
|||||||
+2
-2
@@ -22,8 +22,8 @@ echo ""
|
|||||||
echo "Done. Next steps:"
|
echo "Done. Next steps:"
|
||||||
echo " 1. Install system packages (if not already present):"
|
echo " 1. Install system packages (if not already present):"
|
||||||
echo " sudo apt install ffmpeg bc fonts-dejavu"
|
echo " sudo apt install ffmpeg bc fonts-dejavu"
|
||||||
echo " pip3 install suntime pytz requests"
|
echo " pip3 install pytz requests skyfield"
|
||||||
echo " pip3 install skyfield Pillow numpy scipy # moon jobs (moon-track, moon-phase-monthly)"
|
echo " pip3 install Pillow numpy scipy # moon jobs (moon-track, moon-phase-monthly)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 2. Edit $TARGET/sky-cam.conf"
|
echo " 2. Edit $TARGET/sky-cam.conf"
|
||||||
echo " — SCRIPT_DIR full path to the directory you'll run scripts from"
|
echo " — SCRIPT_DIR full path to the directory you'll run scripts from"
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ ATTR_FADE="$MONTAGE_ATTR_FADE"
|
|||||||
|
|
||||||
# ── Season / movement info ────────────────────────────────────────────────────
|
# ── Season / movement info ────────────────────────────────────────────────────
|
||||||
_season_info="$(python3 "$SCRIPT_DIR/season_info.py" ${DATE_ARG:+"$DATE_ARG"})" || {
|
_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
|
exit 1
|
||||||
}
|
}
|
||||||
eval "$_season_info"
|
eval "$_season_info"
|
||||||
|
|||||||
+51
-7
@@ -1,13 +1,24 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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 pathlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from suntime import Sun
|
|
||||||
|
|
||||||
_here = pathlib.Path(__file__).resolve().parent
|
_here = pathlib.Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
def _read_conf(path):
|
def _read_conf(path):
|
||||||
conf = {}
|
conf = {}
|
||||||
try:
|
try:
|
||||||
@@ -30,6 +41,7 @@ def _read_conf(path):
|
|||||||
pass
|
pass
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
|
|
||||||
conf = _read_conf(_here / 'sky-cam.conf')
|
conf = _read_conf(_here / 'sky-cam.conf')
|
||||||
# .env overrides sky-cam.conf — mirrors the sourcing order at the bottom of 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'))
|
conf.update(_read_conf(_here / '.env'))
|
||||||
@@ -42,9 +54,41 @@ latitude = float(conf['LATITUDE'])
|
|||||||
longitude = float(conf['LONGITUDE'])
|
longitude = float(conf['LONGITUDE'])
|
||||||
tz = pytz.timezone(conf['TIMEZONE'])
|
tz = pytz.timezone(conf['TIMEZONE'])
|
||||||
|
|
||||||
sun = Sun(latitude, longitude)
|
# Search the full local calendar day (midnight→midnight) expressed in UTC.
|
||||||
now = datetime.now(tz)
|
# This bracket is timezone-correct and handles any UTC offset, including large
|
||||||
sunrise_utc = sun.get_sunrise_time(now)
|
# positive offsets (UTC+12/+14) where local midnight falls on the previous UTC day.
|
||||||
sunrise_time = sunrise_utc.astimezone(tz)
|
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'))
|
||||||
|
|||||||
Reference in New Issue
Block a user