LB Download Weather

Hi.

I am wondering if it would be possible to modify LB Download Weather, so that it is also usable to download epw files from locations that have .epw files directly.

It only requires two minimal changes:

  1. detect if url ends with .epw and set folder name

    elif _weather_URL.lower().endswith('.epw'):
        _folder_name = _weather_URL.split('/')[-1][:-4]
    
  2. skip unzip, if url ends with .epw

    if _weather_URL.lower().endswith('.epw'):
        download_file(_weather_URL, epw, True)
    else:
        download_file(_weather_URL, zip_file_path, True)
        unzip_file(zip_file_path)
    
    

The total code block would then become:

```
    
    if all_required_inputs(ghenv.Component):
        # process the URL and check if it is outdated
        _weather_URL = _weather_URL.strip()
    
        if _weather_URL.lower().endswith('.zip'):  # onebuilding URL type
            _folder_name = _weather_URL.split('/')[-1][:-4]
    
        elif _weather_URL.lower().endswith('.epw'):  # NEW: direct EPW URL
            _folder_name = _weather_URL.split('/')[-1][:-4]
    
        else: # dept of energy URL type
            _folder_name = _weather_URL.split('/')[-2]
            if _weather_URL.endswith('/all'):
                repl_section = '{0}/all'.format(_folder_name)
                new_section = '{0}/{0}.zip'.format(_folder_name)
                _weather_URL = _weather_URL.replace(repl_section, new_section)
                _weather_URL = _weather_URL.replace(
                    'www.energyplus.net/weather-download',
                    'energyplus-weather.s3.amazonaws.com')
                _weather_URL = _weather_URL.replace(
                    'energyplus.net/weather-download',
                    'energyplus-weather.s3.amazonaws.com')
                _weather_URL = _weather_URL[:8] + _weather_URL[8:].replace('//', '/')
                msg = 'The weather file URL is out of date.\nThis component ' \
                    'is automatically updating it to the newer version:'
                print(msg)
                print(_weather_URL)
                give_warning(ghenv.Component, msg)
                give_warning(ghenv.Component, _weather_URL)
    
        # create default working_dir
        if _folder_ is None:
            _folder_ = folders.default_epw_folder
        print('Files will be downloaded to: {}'.format(_folder_))
    
        # default file names
        epw = os.path.join(_folder_, _folder_name, _folder_name + '.epw')
        stat = os.path.join(_folder_, _folder_name, _folder_name + '.stat')
        ddy = os.path.join(_folder_, _folder_name, _folder_name + '.ddy')
    
        # download and unzip the files if they do not exist
        if not os.path.isfile(epw) or not os.path.isfile(stat) or not os.path.isfile(ddy):
            if _weather_URL.lower().endswith('.epw'):  # NEW: direct EPW download
                download_file(_weather_URL, epw, True)
    
                # OPTIONAL (still minimal): try to fetch matching stat/ddy if present
                # If you don't want this, delete the next 6 lines.
                try:
                    download_file(_weather_URL[:-4] + '.stat', stat, True)
                except Exception:
                    pass
                try:
                    download_file(_weather_URL[:-4] + '.ddy', ddy, True)
                except Exception:
                    pass
    
            else:  # existing ZIP flow
                zip_file_path = os.path.join(_folder_, _folder_name, _folder_name + '.zip')
                download_file(_weather_URL, zip_file_path, True)
                unzip_file(zip_file_path)
    
        # set output
        epw_file, stat_file, ddy_file = epw, stat, ddy
    
```

And if we were going full throttle, one could add caching of files:

def _get_cache():
    if "LB_DOWNLOAD_WEATHER_CACHE" not in sc.sticky:
        sc.sticky["LB_DOWNLOAD_WEATHER_CACHE"] = {}
    return sc.sticky["LB_DOWNLOAD_WEATHER_CACHE"]

and

# default file names
    epw = os.path.join(_folder_, _folder_name, _folder_name + '.epw')
    stat = os.path.join(_folder_, _folder_name, _folder_name + '.stat')
    ddy = os.path.join(_folder_, _folder_name, _folder_name + '.ddy')
    
    # NEW: init outputs so cache can short-circuit cleanly
    epw_file = stat_file = ddy_file = None
    
    # --- CACHE (NEW) ---
    cache = _get_cache()
    cache_key = _weather_URL  # simplest key; you can also include _folder_ if you prefer
    cached = cache.get(cache_key)

    # If we already have this URL cached and files still exist -> short-circuit
    if cached:
        c_epw = cached.get("epw")
        c_stat = cached.get("stat")  # may be None
        c_ddy = cached.get("ddy")    # may be None

        # require EPW; stat/ddy are optional if previously missing
        if c_epw and os.path.isfile(c_epw):
            if (c_stat is None or os.path.isfile(c_stat)) and (c_ddy is None or os.path.isfile(c_ddy)):
                epw, stat, ddy = c_epw, c_stat, c_ddy
                epw_file, stat_file, ddy_file = epw, stat, ddy

    # download and unzip the files if they do not exist (or not cached)
    if epw_file is None:  # only runs if cache did not short-circuit
        if not os.path.isfile(epw) or (stat is not None and not os.path.isfile(stat)) or (ddy is not None and not os.path.isfile(ddy)):
            if _weather_URL.lower().endswith('.epw'):  # direct EPW download
                download_file(_weather_URL, epw, True)

                # OPTIONAL: try to fetch matching stat/ddy ONCE per session
                # If a prior run proved they don't exist, don't retry.
                missing = cached.get("missing", {}) if cached else {}

                # STAT
                if not missing.get("stat", False) and not os.path.isfile(stat):
                    try:
                        download_file(_weather_URL[:-4] + '.stat', stat, True)
                    except Exception:
                        stat = None
                        missing["stat"] = True

                # DDY
                if not missing.get("ddy", False) and not os.path.isfile(ddy):
                    try:
                        download_file(_weather_URL[:-4] + '.ddy', ddy, True)
                    except Exception:
                        ddy = None
                        missing["ddy"] = True

                # update cache (NEW)
                cache[cache_key] = {"epw": epw, "stat": stat, "ddy": ddy, "missing": missing}

            else:  # ZIP flow
                zip_file_path = os.path.join(_folder_, _folder_name, _folder_name + '.zip')
                download_file(_weather_URL, zip_file_path, True)
                unzip_file(zip_file_path)

                # update cache (NEW)
                cache[cache_key] = {"epw": epw, "stat": stat, "ddy": ddy, "missing": {}}

        # set output (unchanged)
        epw_file, stat_file, ddy_file = epw, stat, ddy

But this might be an overkill.

Hey @LittleBuddha ,

I would do the caching a little differently (checking to see whether the downloaded file path already exists rather than adding it into sticky) but I’m not opposed to tweaking the official component with your suggestion such that it can download URLs pointing only to an .epw file and not a .zip.

Do you mind my asking what database of URLs you are planning to use this type of changed component for? Is it a publicly available data set of EPWs? Or is it something internal to an office setting?

I’m just trying to gauge how many people might use the component like this so that I have a sense of what might be needed to keep it working the way people want in the future.

That’s great to hear @chris :wink:

My specific usage case is using the new dataset for the EU that is available at www.Climatedataforbuildings.eu directly as .epw

It is the newest and highest quality dataset for the EU, and easily navigable/available through that site.

And I can see your point on the caching. You are the master, I am but a padawan.

1 Like