moon_detect.py
- detect_moon() accepts saturated_threshold / min_roundness / max_halo_ratio
so crescent phases (dim, non-circular arc) can be detected with relaxed
thresholds without changing defaults for full/quarter detection.
moon_phase.py
- crescent_times_in_range(): 2-hour scan returning the UTC moment illumination
crosses a target fraction (default 28%) on the waxing or waning side.
Used for scheduling just like phase_events_in_range() for named phases.
moon_composite.py
- Remove _apply_phase_shadow() from composite_full_moon. NASA SVS Dial-a-Moon
renders already include the correct terminator, libration and earthshine for
the exact hour; applying the shadow on top double-darkened the unlit limb on
every non-full phase. The function stays available for callers that need it.
moon_phase_monthly.py
- Add waxing-crescent (🌒) and waning-crescent (🌘) to PHASE_SPEC.
Timing via crescent_times_in_range(); scheduling identical to other phases.
- CRESCENT_* tuning constants (all overridable from sky-cam.conf):
MOON_CRESCENT_TARGET_ILLUM default 0.28
MOON_CRESCENT_MIN_QUALITY default 0.35
MOON_CRESCENT_SATURATED_THR default 180
MOON_CRESCENT_MIN_ROUNDNESS default 0.15
MOON_CRESCENT_MAX_HALO_RATIO default 12.0
- run_phase() and auto_run() branch on spec['crescent'] to use crescent
timing and detection params.
- Atmospheric background naturally captures twilight colours (dawn for waning
crescent, dusk/dawn for waxing) from the real east frame.
https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
Two new jobs operate on the SUNRISE_CAM, sharing three Python helpers
(moon_phase, moon_detect, moon_composite) and one cached lunar texture:
- moon-track.sh: nightly batch detects the moon in each east frame,
crops a 480x480 box around it, stitches into an mp4 that holds the
moon roughly centred while clouds and stars drift past.
- moon-phase-monthly.sh: daily check that runs whichever phase composite
is due that day. Handles full moon (posts D+3), first quarter (D+2,
best-effort due to daytime-only geometry from east), and third quarter
(D+2). Picks the frame closest in time to the exact phase moment that
meets quality / altitude / illumination thresholds, then composites
the cached lunar texture into it -- sky/halo/parallactic-angle/timing
real from east, surface detail borrowed from the reference image.
Honest-by-design: a 38-px white blob from a wide-field IP camera cannot
be enhanced into crater detail by software. The composite makes the
borrowing explicit and constrains everything else (when, where, sky,
orientation) to match what east actually saw.
install.sh now downloads the skyfield ephemeris (de421.bsp) and the
default lunar reference (Wikipedia CC BY-SA full-moon photo) on first
run. Both can be overridden via .env.
https://claude.ai/code/session_015PBVDESC3KLMbq1LpA6qLn