New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

epwtools

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

epwtools

Python SDK and CLI for epw.tools — generate EPW/DDY weather files from MERRA-2, ERA5 and CMIP6

pipPyPI
Version
0.5.1
Weekly downloads
117
Maintainers
1
Created

EPW.tools

Every weather file you'll ever need.

A web application + API for generating high-quality weather files for building energy simulation, solar design, climate research, agriculture, insurance and more.

What it does

EPW.tools fuses measured station observations with global reanalysis and satellite-derived solar data to produce dense, internally consistent weather files in over a dozen formats.

LayerSource
BackboneERA5 (ECMWF) and MERRA-2 (NASA) reanalysis
StationsNOAA ISD via Meteostat (~3 500 curated stations worldwide)
SolarNREL NSRDB / PSM v3 where available, Zhang–Huang fallback
Future climateNASA NEX-GDDP-CMIP6 with Belcher 2005 morphing
Design conditionsASHRAE Handbook of Fundamentals

Measured station data takes priority; small gaps are interpolated; longer gaps are filled from reanalysis. Every file passes a battery of physical-plausibility checks before release.

See RESOURCES.md for the full source list and references.

Python SDK

The epwtools Python package provides a typed client for the REST API plus a weatherproof CLI:

pip install epwtools

Quick start

from epwtools import EPWClient

client = EPWClient(api_key="your-key-here")  # or set EPWTOOLS_API_KEY

# Single-year AMY
epw = client.generate(lat=40.71, lon=-74.01, year=2023, name="NewYork")

# Typical Meteorological Year
epw = client.tmy(lat=51.50, lon=-0.12, start=2005, end=2024, name="London")

# Future climate (CMIP6, SSP2-4.5, 2050)
epw = client.future(lat=48.85, lon=2.35, scenario="ssp245", horizon=2050)

# Multi-GCM ensemble (one EPW per CMIP6 model — for uncertainty bands)
epws = client.ensemble(lat=48.85, lon=2.35, scenario="ssp245", horizon=2050)

# Climate stress-test for a portfolio (no credits consumed)
table = client.portfolio_stress_test(
    [{"lat": 40.71, "lon": -74.01, "label": "NYC"},
     {"lat": 51.50, "lon": -0.12,  "label": "London"}],
    scenario="ssp245", horizon=2050,
)

Real-time progress (SSE)

resp = client._post("/generate/individual", json={...})
for ev in client.stream(resp["job_id"]):
    if ev["type"] == "log":
        print("  ", ev["line"])
    elif ev["type"] == "status" and ev["status"] == "complete":
        break

Endpoint namespaces

The client exposes every API endpoint under five thin namespaces — use them when you want to reach a specific endpoint that isn't covered by the high-level generation methods:

client.tools.uhi_adjust("base.epw", ucz="UCZ-2")
client.tools.koppen("file.epw")              # → {"koppen": "Cfa", ...}
client.tools.solar_calibrate("file.epw")     # PSM3 blend (US)
client.tools.gap_fill("partial.epw")
client.tools.epw_diff("a.epw", "b.epw")      # → hourly delta stats

client.epw.wind_rose(job_id, "out.epw")      # 16 dirs × 6 speed bins
client.epw.heatmap(job_id, "out.epw", variable="dry_bulb")
client.epw.psychro(job_id, "out.epw")

client.reports.solar("file.epw")
client.reports.viticulture("file.epw")       # GDD, Huglin, Winkler
client.reports.datacenter("file.epw")        # free-cooling hours
client.reports.insurance("file.epw", heat_threshold=38)

client.data.cities()                         # ~3,000 curated cities
client.data.stations_isd(40.7, -74.0)        # NOAA ISD nearby
client.data.cmip6_models()                   # available GCMs
client.data.design_conditions(40.7, -74.0)   # ASHRAE for nearest station

client.jobs.get(job_id)
client.jobs.cancel(job_id)
client.jobs.csv(job_id, "out.epw")           # download CSV alt

Async client (for portfolio workloads)

pip install 'epwtools[aio]'
import asyncio
from epwtools import AsyncEPWClient

async def main():
    async with AsyncEPWClient(api_key="...", max_concurrency=8) as client:
        paths = await asyncio.gather(*[
            client.generate(lat=lat, lon=lon, year=2023, name=label)
            for (lat, lon, label) in PORTFOLIO
        ])
    return paths

asyncio.run(main())

CLI

weatherproof generate --lat 39.74 --lon -104.98 --year 2022 --name Denver
weatherproof tmy      --lat 40.71 --lon -74.01 --start 2005 --end 2024
weatherproof future   --lat 48.85 --lon 2.35   --scenario ssp245 --horizon 2050
weatherproof export   myfile.epw --format xlsx

The CLI honours EPWTOOLS_API_KEY and EPWTOOLS_API_URL env vars (or pass --api-url). Self-hosted backends work too — just point EPWTOOLS_API_URL at your instance.

AI assistants (MCP server)

EPW.tools ships a Model Context Protocol server, so AI assistants (Claude Desktop, Cursor, and other MCP-capable agents) can generate weather files directly — no browser. Tools exposed: generate_epw, generate_tmy, generate_future_climate, generate_forecast, get_design_conditions, get_nearest_stations, get_job_result.

Every generate_* tool takes an optional save_to folder: the EPW, DDY and STAT are saved there under one base name, ready for EnergyPlus or OpenStudio. get_design_conditions returns heating and cooling design conditions in one of two modes that are never mixed: ashrae_method (the ASHRAE Handbook method, replicated and validated) or enhanced (values at the site, for today's climate, with 90 % ranges). Values are free and need no key; the ASHRAE-method DDY is free and the Enhanced DDY costs 1 credit.

Add this to your MCP client config (one line, nothing to clone — it uses uv to run on demand):

{
  "mcpServers": {
    "epw-tools": {
      "command": "uvx",
      "args": ["--from", "epwtools[mcp]", "epw-tools-mcp"],
      "env": { "EPWTOOLS_API_KEY": "epw_your_key_here" }
    }
  }
}

Prefer pip? pip install 'epwtools[mcp]', then set the command to epw-tools-mcp. The API base defaults to the public backend (https://epw.tools/api); override with EPWTOOLS_API_BASE for a self-hosted instance. Get an API key at epw.tools — most generated files use one credit (a future-climate file uses three), and new accounts start with free credits.

With OpenStudio-MCP (natural-language energy modelling)

OpenStudio-MCP lets an AI assistant build and simulate EnergyPlus models, but it needs a weather file on disk. Run both servers and EPW.tools supplies the weather for any location, year or future climate:

{
  "mcpServers": {
    "epw-tools": {
      "command": "uvx",
      "args": ["--from", "epwtools[mcp]", "epw-tools-mcp"],
      "env": { "EPWTOOLS_API_KEY": "epw_your_key_here" }
    },
    "openstudio-mcp": {
      "command": "docker",
      "args": ["run", "--rm", "-i",
               "-v", "/path/to/weather:/inputs:ro", "-v", "/path/to/runs:/runs",
               "nrel/openstudio-mcp:v1.2.1", "openstudio-mcp"]
    }
  }
}

Then ask, for example:

  • "Get a 2023 weather file for Lugano, save it to /path/to/weather, and simulate a small office there." The assistant calls generate_epw(..., save_to="/path/to/weather"), then OpenStudio-MCP's create_new_building(weather_file="/inputs/Lugano_2023.epw").
  • "Same office in the 2050 climate (SSP2-4.5)." generate_future_climate(..., save_to=...).
  • "Size it with EPW.tools Enhanced design days." get_design_conditions(mode="enhanced", save_to="/path/to/weather", ddy_name="Lugano_2023") replaces the DDY before the location is set.

Features

Generate

  • Single-year and multi-year EPW files for any lat/lon
  • Composite-year files that blend multiple seasons
  • TMY selection via Sandia / Finkelstein–Schafer
  • Future-climate morphing through 2100 from CMIP6 scenarios
  • Ensemble runs across GCMs
  • Batch processing from a CSV of locations

Modify

  • Altitude / micro-climate correction (lapse rate, barometric, wind log-law)
  • Monthly solar calibration against reference data
  • Urban heat-island morphing
  • Wildfire smoke / atmospheric attenuation overlay

Inspect

  • Visualise any EPW (psychrometric, hourly, monthly)
  • Validate against ASHRAE / EnergyPlus range checks
  • Köppen–Geiger and ASHRAE / IECC climate-zone classification
  • Heating, cooling and billing degree-day reports
  • Independent solar sanity check (Zhang–Huang 2002)

Output formats

EPW, DDY, STAT, WEA (Radiance), CLM (ESP-r), PVSyst .met, CSV, JSON, Excel, Parquet, NetCDF (CF-1.8), and a one-click .zip bundle.

Project structure

epw.tools/
├── backend/                  # FastAPI + pandas + xarray
│   ├── app.py                # API routes + job management
│   ├── methods.py            # Core methods
│   ├── ssl_utils.py
│   ├── resources/            # Static lookup data (design conditions, etc.)
│   ├── outputs/              # Generated files (auto-created)
│   └── requirements.txt
├── frontend/                 # React + Vite + Tailwind
│   ├── src/
│   │   ├── App.jsx
│   │   ├── api/client.js
│   │   ├── hooks/
│   │   └── components/
│   └── package.json
├── run_backend.py            # Convenience entry point
├── RESOURCES.md              # Data sources & methodology
└── README.md

Setup

Quick start (5 minutes)

Generate a single-year EPW for any lat/lon from the command line:

git clone https://github.com/your-org/epwtools.git
cd epwtools
python3 -m venv .venv && source .venv/bin/activate
pip install -r backend/requirements.txt
python run_backend.py &                     # backend on :8000
sleep 3

# Submit a job: New York City, 2022, with default fusion + QC
curl -X POST http://localhost:8000/api/generate/individual \
  -H "Content-Type: application/json" \
  -d '{"lat":40.7,"lon":-74.0,"year":2022,"location_name":"NYC"}'
# → returns {"job_id":"abc-..."}

# Poll until status=="completed", then download:
curl -s http://localhost:8000/api/jobs/abc-.../download/NYC_2022.epw -o nyc.epw

The full UI is at http://localhost:5173 after cd frontend && npm install && npm run dev.

Compare two EPWs (e.g. baseline vs UHI-morphed):

python tools/epw_diff.py base.epw morphed.epw --summary
# {"row_count":8760,"max_dT_dry_bulb":4.0,"mean_dT_dry_bulb":1.85,...}

Backend

python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r backend/requirements.txt
python run_backend.py            # → http://localhost:8000

Frontend

cd frontend
npm install
npm run dev                      # → http://localhost:5173

The Vite dev server proxies /api requests to the backend automatically.

API overview

MethodEndpointDescription
POST/api/generate/individualSingle-year EPW job
POST/api/generate/multi-yearMulti-year EPW job
POST/api/generate/compositeComposite-year EPW
POST/api/generate/tmyTMY (Sandia / Finkelstein–Schafer)
POST/api/generate/futureFuture-climate (CMIP6 morphing)
POST/api/generate/ensembleMulti-GCM ensemble
POST/api/generate/meteredRaw measured-data download
POST/api/generate/csv-batchBulk job from CSV
POST/api/tools/altitude-correctApply lapse / pressure / wind correction
POST/api/tools/solar-calibrateMonthly solar calibration
POST/api/tools/billing-ddHeating / cooling / billing DD
POST/api/tools/koppenKöppen–Geiger classification
POST/api/tools/solar-checkZhang–Huang solar cross-check
POST/api/tools/export-format/{fmt}Export EPW to alternative format
GET/api/jobs/{job_id}Poll job status / logs / result
GET/api/jobs/{job_id}/streamSSE stream for real-time logs
GET/api/jobs/{job_id}/download/{filename}Download generated file

License

Proprietary. All rights reserved.

Keywords

ashrae

FAQs

Related posts