api / scripts /download_ims_data.py
safraeli's picture
Deploy: 2026 sensor migration + redesign + bucket B endpoints
13fc29d verified
Raw
History Blame Contribute Delete
3.87 kB
"""
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()