""" Download IMS weather data for station 43 (Sde Boker) and cache to Data/ims/. Resamples 10min to 15min. Use --list-channels to discover channel IDs for RH, Rain, WS, BP. Usage: python -m scripts.download_ims_data --list-channels python -m scripts.download_ims_data --from 2024-01-01 --to 2024-12-31 python -m scripts.download_ims_data --years 2 """ from __future__ import annotations import argparse import sys from pathlib import Path # Project root on path for config and src PROJECT_ROOT = Path(__file__).resolve().parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) try: from dotenv import load_dotenv load_dotenv(PROJECT_ROOT / ".env") except ImportError: pass def main() -> None: parser = argparse.ArgumentParser( description="Fetch IMS station 43 data and cache to Data/ims/ (15min resolution)." ) parser.add_argument( "--list-channels", action="store_true", help="List channel IDs and names for station 43 (to find RH, Rain, WS, BP).", ) parser.add_argument( "--from", dest="from_date", metavar="YYYY-MM-DD", help="Start date (inclusive).", ) parser.add_argument( "--to", dest="to_date", metavar="YYYY-MM-DD", help="End date (inclusive).", ) parser.add_argument( "--years", type=float, default=2, metavar="N", help="If --from/--to not set, fetch last N years (default: 2).", ) parser.add_argument( "--chunk-days", type=int, default=7, metavar="D", help="Split range into D-day chunks (default: 7 for better API success). Use 0 to disable chunking.", ) args = parser.parse_args() from src.ims_client import IMSClient from config import settings client = IMSClient() if args.list_channels: try: channels = client.list_channels(settings.IMS_STATION_ID) except Exception as e: print(f"Error fetching station metadata: {e}", file=sys.stderr) sys.exit(1) if not channels: print("No channels returned. Check API response structure.") sys.exit(0) print(f"Station {settings.IMS_STATION_ID} channels:") print("-" * 60) for ch in sorted(channels, key=lambda x: (x.get("channelId") or 0)): cid = ch.get("channelId", "?") name = ch.get("name", "?") units = ch.get("units", "") active = ch.get("active", True) print(f" {cid:>4} {name:<12} {units:<8} active={active}") return # Determine date range from datetime import datetime, timedelta, timezone end = datetime.now(timezone.utc).date() if args.from_date and args.to_date: start = datetime.strptime(args.from_date, "%Y-%m-%d").date() end = datetime.strptime(args.to_date, "%Y-%m-%d").date() elif args.from_date: start = datetime.strptime(args.from_date, "%Y-%m-%d").date() else: start = end - timedelta(days=int(args.years * 365.25)) from_s = start.strftime("%Y-%m-%d") to_s = end.strftime("%Y-%m-%d") chunk_days = args.chunk_days if args.chunk_days else None print(f"Fetching IMS station {settings.IMS_STATION_ID} from {from_s} to {to_s} (chunk_days={chunk_days})...") try: df = client.fetch_and_cache(from_s, to_s, chunk_days=chunk_days) except Exception as e: print(f"Error: {e}", file=sys.stderr) sys.exit(1) if df.empty: print("No data returned. Check token and date range.") sys.exit(1) out_path = settings.IMS_CACHE_DIR / "ims_merged_15min.csv" print(f"Saved {len(df)} rows (15min) to {out_path}") print(f"Columns: {list(df.columns)}") if __name__ == "__main__": main()