- moon_composite.py: remove _make_atmosphere_layer() and all atmosphere parameters from render_phase_closeup(); add when_utc parameter and apply parallactic angle rotation so the NASA disk is oriented to match east's sky - moon_phase_monthly.py: change obs time default to 22:00 (aligns with NASA hourly renders); scan east frames in 22:00-23:00 window; binary go/no-go (quality >= MIN_QUALITY = post, no clear shot = skip entirely); remove _atmosphere_opacity_from_quality(), ATMOSPHERE_BLUR, CLOUDY_POST_ENABLED - sky-cam.conf: update MOON_OBS_TIME_LOCAL to 22:00, remove MOON_OBS_WINDOW_MIN, remove the atmospheric overlay and cloudy fallback sections and their config variables - test_moon_composite.py: single clean test — fetch NASA for 22:00 UTC on 2026-04-29, verify east frame quality, render with parallactic angle; no procedural fallback https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
93 lines
2.8 KiB
Python
93 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""test_moon_composite.py — render a phase composite using real NASA data.
|
|
|
|
Simulates what moon_phase_monthly.py does on the night of a full moon:
|
|
|
|
1. Fetch the NASA SVS Dial-a-Moon render for 2026-04-29T22:00Z.
|
|
2. Load the east camera frame (21-07-00.jpg) and check for a clear moon.
|
|
3. If clear: render — NASA moon with parallactic angle rotation → test_composite_out.jpg.
|
|
4. If not clear: exit with a message (no fallback image).
|
|
|
|
Run from the sky-cam directory:
|
|
|
|
python3 test_moon_composite.py
|
|
|
|
Requires internet access to reach svs.gsfc.nasa.gov.
|
|
"""
|
|
|
|
import pathlib
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
HERE = pathlib.Path(__file__).resolve().parent
|
|
sys.path.insert(0, str(HERE))
|
|
|
|
EAST_FRAME = HERE / '21-07-00.jpg'
|
|
OUT_PATH = HERE / 'test_composite_out.jpg'
|
|
|
|
# Obs time: 22:00 UTC on 2026-04-29 — aligns directly with NASA hourly renders.
|
|
NASA_FETCH_UTC = datetime(2026, 4, 29, 22, 0, tzinfo=timezone.utc)
|
|
|
|
MIN_QUALITY = 0.55
|
|
|
|
|
|
def main():
|
|
if not EAST_FRAME.exists():
|
|
print(f'ERROR: missing {EAST_FRAME}', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print('=== moon composite test ===')
|
|
print(f'east frame : {EAST_FRAME.name} (2026-04-29 21:07 UTC)')
|
|
print(f'NASA time : {NASA_FETCH_UTC.strftime("%Y-%m-%dT%H:00Z")}')
|
|
print()
|
|
|
|
# 1. Check east frame for clear moon detection
|
|
print(f'checking moon in {EAST_FRAME.name} ...')
|
|
try:
|
|
from moon_detect import detect_moon
|
|
det = detect_moon(str(EAST_FRAME))
|
|
quality = det.quality if det is not None else None
|
|
except Exception as e:
|
|
print(f' detection failed: {e}', file=sys.stderr)
|
|
sys.exit(2)
|
|
|
|
if quality is None or quality < MIN_QUALITY:
|
|
print(f' quality={quality} — no clear moon detection — skipping (no fallback)')
|
|
sys.exit(0)
|
|
|
|
print(f' quality={quality:.3f} — clear shot confirmed')
|
|
print()
|
|
|
|
# 2. Fetch NASA Dial-a-Moon
|
|
print(f'fetching NASA Dial-a-Moon for {NASA_FETCH_UTC.strftime("%Y-%m-%dT%H:00Z")} ...')
|
|
try:
|
|
import moon_dialamoon
|
|
nasa_path = moon_dialamoon.fetch_for_time(NASA_FETCH_UTC)
|
|
print(f' cached at {nasa_path}')
|
|
except Exception as e:
|
|
print(f' NASA fetch failed: {e}', file=sys.stderr)
|
|
sys.exit(3)
|
|
print()
|
|
|
|
# 3. Render with parallactic angle rotation
|
|
from moon_composite import render_phase_closeup
|
|
caption = (
|
|
f'Full Moon — April 2026 — '
|
|
f'sky-cam east 2026-04-29 22:00 UTC — '
|
|
f'NASA SVS Dial-a-Moon'
|
|
)
|
|
print(f'rendering {OUT_PATH.name} ...')
|
|
render_phase_closeup(
|
|
nasa_render_path=str(nasa_path),
|
|
out_path=str(OUT_PATH),
|
|
output_size=(1920, 1080),
|
|
moon_height_pct=0.88,
|
|
caption=caption,
|
|
when_utc=NASA_FETCH_UTC,
|
|
)
|
|
print(f'done -> {OUT_PATH}')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|