Use real sunset/sunrise for dark window; pick frame closest to exact phase

moon_phase.py: add sun_events_in_range() — returns actual sunset/sunrise
transitions via skyfield almanac, accurate to within a minute

moon_phase_monthly.py:
- _dark_moon_intervals(): replace sun-altitude threshold sampling with
  actual sunset/sunrise times; dark window = sunset + DARK_START_MIN to
  next sunrise; moon-above-horizon check still sampled every 10 min within
  each night; polar fallback if no sun events found
- run_phase(): sort dark-window frames by proximity to exact phase moment
  before scanning; first clear detection = the frame temporally closest to
  the moon being precisely full/at quarter, not just the first in time order
- Replace DARK_SKY_SUN_ALT_DEG with DARK_START_MIN (default 30 min)

sky-cam.conf: replace MOON_DARK_SKY_SUN_ALT_DEG with MOON_DARK_START_MIN=30;
update comments to explain ±24h window, sunset+30 start, closest-frame logic,
and how the 01:30 and 23:55 edge cases are handled

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
This commit is contained in:
Claude
2026-05-01 22:38:04 +00:00
parent 3fc77ab75e
commit 975c9cc2eb
3 changed files with 107 additions and 43 deletions
+20 -11
View File
@@ -492,20 +492,29 @@ MOON_TRACK_CRF=24 # output mp4 CRF
MOON_TRACK_RETENTION_DAYS=90 # delete tracker mp4s older than this; 0 = forever
# Dark-sky observation window ─────────────────────────────────────────────────
# The script searches ±24h around the exact phase moment for east frames where:
# 1. The sun is below MOON_DARK_SKY_SUN_ALT_DEG (sky is dark)
# 2. The moon is above MOON_MIN_ALTITUDE_DEG (moon is visible above trees)
# The script searches ±24h around the exact phase moment using actual computed
# sunset and sunrise times for the configured location. The dark window for
# each night starts at (sunset + MOON_DARK_START_MIN) and ends at sunrise.
# Within that window, only frames where the moon is above MOON_MIN_ALTITUDE_DEG
# are considered.
#
# Sun altitude thresholds:
# -6 civil twilight — noticeably dark, bright stars visible (default)
# -12 nautical — horizon barely visible
# -18 astronomical — fully dark, no twilight glow
# The east camera faces east, so the moon is visible to it from moonrise through
# roughly south — typically from dusk through midnight for a full moon.
# MOON_DARK_START_MIN=30 means the script starts looking 30 min after the sun
# sets, when the sky is dark enough for a clean moon shot but east can still
# catch the moon low on the eastern horizon.
#
# The first east frame in that window with quality >= MOON_MIN_QUALITY is used.
# Its exact timestamp drives the NASA Dial-a-Moon fetch (rounded to nearest hour)
# and the parallactic angle rotation. The caption shows illumination% at that
# Of all qualifying frames, the one temporally closest to the exact phase moment
# is used (not the first one). This picks the frame when the moon was most
# precisely full / at quarter. Its timestamp drives the NASA Dial-a-Moon fetch
# and the parallactic angle rotation; the caption shows illumination% at that
# moment. If no clear frame is found, the month is skipped entirely.
MOON_DARK_SKY_SUN_ALT_DEG=-6
#
# If the phase falls early in the day (e.g. 01:30 local), the ±24h window
# covers the previous evening through the following dusk — both nights where
# the moon is essentially full. If the phase falls just before midnight
# (e.g. 23:55), both the same evening and the next morning are included.
MOON_DARK_START_MIN=30
# Post delay ──────────────────────────────────────────────────────────────────
# How many days after the exact phase to run the post. The post delay gives