Merge pull request #68 from outis1one/claude/fix-sunrise-sunset-observer-BA0Iy
Claude/fix sunrise sunset observer ba0 iy
This commit is contained in:
@@ -296,14 +296,19 @@ Replace the date list with whatever range you need. Each run produces one `*-fi
|
||||
python3 moon_detect.py BASE_DIR/east/2026-04-29/21-07-00.jpg --debug /tmp/dbg.png
|
||||
python3 moon_phase.py info 2026-04-29T21:07:00Z
|
||||
|
||||
# Smoke-test moon ephemeris + sunrise/sunset almanac against the last full moon
|
||||
# End-to-end test: fetch NASA render + produce composite for the last full moon
|
||||
python3 test_last_full_moon.py
|
||||
# Output: test_last_full_moon_out.jpg
|
||||
```
|
||||
|
||||
`test_last_full_moon.py` finds the most recent full moon, prints illumination, phase angle,
|
||||
altitude/azimuth, and parallactic angle, then lists the sunrise and sunset for that day.
|
||||
It exercises the full skyfield stack including the `sun_events_in_range()` almanac call —
|
||||
useful after updating skyfield or changing observer config.
|
||||
`test_last_full_moon.py` is equivalent to `moon-phase-monthly.sh --phase full --no-upload` for
|
||||
the most recent full moon, with the output redirected to `test_last_full_moon_out.jpg`. It runs
|
||||
the complete production pipeline: dark-window filtering, east-frame moon detection, NASA
|
||||
Dial-a-Moon fetch, and `render_phase_closeup` with the full caption. It also calls
|
||||
`sun_events_in_range()` explicitly before the main pipeline as a regression check for the
|
||||
bare-topos fix.
|
||||
|
||||
Useful after updating skyfield, changing `LATITUDE`/`LONGITUDE`, or touching the compositing code.
|
||||
|
||||
**Posting schedule**:
|
||||
|
||||
|
||||
+27
-34
@@ -1,10 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
"""test_last_full_moon.py — smoke-test moon_phase.py against the most recent full moon.
|
||||
"""test_last_full_moon.py — run the full moon pipeline for the most recent full moon.
|
||||
|
||||
Exercises:
|
||||
- full_moons_in_range() — phase detection
|
||||
- sun_events_in_range() — sunrise/sunset almanac (requires bare topos, not earth+topos)
|
||||
- illumination() / altaz() / parallactic_angle()
|
||||
Identical to `moon-phase-monthly.sh --phase full --no-upload` except the
|
||||
output is written to test_last_full_moon_out.jpg in the sky-cam directory
|
||||
instead of the normal movies tree.
|
||||
|
||||
Includes east-frame detection, dark-window filtering, NASA Dial-a-Moon
|
||||
fetch, and render_phase_closeup — the complete production path.
|
||||
Also calls sun_events_in_range() explicitly as a regression check for
|
||||
the sunrise_sunset() bare-topos fix.
|
||||
|
||||
Run from the sky-cam directory:
|
||||
|
||||
@@ -18,48 +22,37 @@ from datetime import datetime, timedelta, timezone
|
||||
HERE = pathlib.Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(HERE))
|
||||
|
||||
import moon_phase as mp
|
||||
OUT_PATH = HERE / 'test_last_full_moon_out.jpg'
|
||||
|
||||
|
||||
def main() -> int:
|
||||
now = datetime.now(timezone.utc)
|
||||
import moon_phase as mp
|
||||
import moon_phase_monthly as mpm
|
||||
|
||||
# Last full moon: search back up to 35 days
|
||||
# ── Regression check: sun_events_in_range() (bare-topos fix) ─────────────
|
||||
now = datetime.now(timezone.utc)
|
||||
candidates = mp.full_moons_in_range(now - timedelta(days=35), now)
|
||||
if not candidates:
|
||||
print("ERROR: no full moon found in the last 35 days", file=sys.stderr)
|
||||
return 1
|
||||
fm = candidates[-1]
|
||||
|
||||
print(f"last full moon (UTC) : {fm.strftime('%Y-%m-%dT%H:%M:%SZ')}")
|
||||
print(f"local : {mp._format_local(fm)}")
|
||||
|
||||
# Moon stats at exact full moon moment
|
||||
illum = mp.illumination(fm)
|
||||
pa = mp.phase_angle(fm)
|
||||
alt, az = mp.altaz(fm)
|
||||
para = mp.parallactic_angle(fm)
|
||||
print(f"illumination : {illum:.4f} ({illum*100:.1f}%)")
|
||||
print(f"phase angle : {pa:.2f}° (0° = full)")
|
||||
print(f"altitude / azimuth : {alt:.2f}° / {az:.2f}°")
|
||||
print(f"parallactic angle : {para:.2f}°")
|
||||
print()
|
||||
|
||||
# Sunrise/sunset for the 24-hour window around the full moon — exercises the fix
|
||||
day_start = fm.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
day_end = day_start + timedelta(days=1)
|
||||
events = mp.sun_events_in_range(day_start, day_end)
|
||||
if events:
|
||||
print(f"sun events on {day_start.strftime('%Y-%m-%d')} (UTC):")
|
||||
events = mp.sun_events_in_range(day_start, day_start + timedelta(days=1))
|
||||
print(f"sun events on {day_start.strftime('%Y-%m-%d')} UTC (topos fix check):")
|
||||
for t, is_rise in events:
|
||||
label = "sunrise" if is_rise else "sunset "
|
||||
print(f" {label} {t.strftime('%H:%M:%S')} UTC ({mp._format_local(t)})")
|
||||
else:
|
||||
print(f"no sun events found on {day_start.strftime('%Y-%m-%d')} (polar location?)")
|
||||
|
||||
print(f" {'sunrise' if is_rise else 'sunset '} {t.strftime('%H:%M:%S')} UTC")
|
||||
print()
|
||||
print("OK")
|
||||
return 0
|
||||
|
||||
# ── Full production pipeline ──────────────────────────────────────────────
|
||||
return mpm.run_phase(
|
||||
phase='full',
|
||||
target_utc=fm,
|
||||
cam=mpm.SUNRISE_CAM,
|
||||
dry_run=False,
|
||||
no_upload=True,
|
||||
out_path=str(OUT_PATH),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user