Commit Graph
5 Commits
Author SHA1 Message Date
Claude 29a864375b Add waxing/waning crescent phases; fix phase-shadow double-application
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
2026-05-03 23:21:44 +00:00
Claude 318af0dbf5 fix: pass bare topos to sunrise_sunset(), not earth+topos observer
skyfield's sunrise_sunset() internally computes ephemeris['earth'] + topos,
so passing the already-combined _observer caused a double-add ValueError.
Store _topos separately and use it only for almanac calls; _observer
(earth + topos) continues to be used for direct .at() observations.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:43:03 +00:00
Claude 975c9cc2eb 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
2026-05-01 22:38:04 +00:00
Claude 3fc77ab75e Expand obs window to full dark+moon period; label with illumination%
moon_phase.py: add sun_altaz() to compute sun altitude for dark-sky check

moon_phase_monthly.py:
- Replace fixed 22:00-23:00 window with dynamic dark+moon intervals:
  sample every 10 min across ±24h of the phase moment, keep blocks where
  sun < DARK_SKY_SUN_ALT_DEG and moon > MIN_ALTITUDE — covers the full
  night the moon is actually visible in a dark sky regardless of month
- First east frame with quality >= MIN_QUALITY in that window wins
- Illumination% computed at the detection time and shown in the image
  caption and Mattermost message
- Remove OBS_TIME_H/M; add DARK_SKY_SUN_ALT_DEG config var

sky-cam.conf: replace MOON_OBS_TIME_LOCAL with MOON_DARK_SKY_SUN_ALT_DEG=-6
and explain the sun-altitude threshold options

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 22:32:16 +00:00
Claude 5fb7ff09a3 Add nightly moon-track timelapse and monthly moon-phase composites
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
2026-04-30 11:40:11 +00:00