Air quality - Sentinel-5P NO2 monthly mean via openEO¶
The sentinel-5p-no2-monthly recipe loads TROPOMI tropospheric NO2 and reduces it to a monthly mean server-side (NetCDF). A useful starting point for air-quality and emissions monitoring over a city or region. We use a box over the Benelux (a well-known NO2 hotspot) and one month.
pip install earthlens[openeo]
Setup¶
First the imports. earthlens provides the unified EarthLens entry point; os and pathlib are used to probe for openEO credentials below.
import os
from pathlib import Path
from earthlens import EarthLens
Credentials¶
openEO authenticates with CDSE via OIDC. The download cell below runs for real when credentials are present (env OPENEO_CLIENT_ID / OPENEO_CLIENT_SECRET, or a cached refresh token from a prior interactive login) and prints a skip note otherwise - so this notebook executes cleanly with or without secrets. See the Authentication page.
has_openeo_credentials() checks each supported credential source in turn: the headless client-id/secret pair, a refresh token, or a cached ~/.openeo login.
def has_openeo_credentials() -> bool:
"""Whether some openEO OIDC credential source is available."""
if os.environ.get("OPENEO_CLIENT_ID") and os.environ.get("OPENEO_CLIENT_SECRET"):
return True
if os.environ.get("OPENEO_REFRESH_TOKEN"):
return True
return (Path.home() / ".openeo").exists()
run_or_skip() wraps the live download() so the notebook runs top-to-bottom with no errors whether or not CDSE OIDC credentials are configured (so the docs build never needs secrets): it downloads when credentials exist and prints a skip note otherwise.
def run_or_skip(facade, **download_kwargs):
"""Run the live download when credentials exist, else print a skip note.
Keeps the notebook executing top-to-bottom with no errors whether or not
CDSE OIDC credentials are configured (so the docs build never needs secrets).
"""
if not has_openeo_credentials():
print(
"No openEO OIDC credentials found - skipping the live download.\n"
"Set OPENEO_CLIENT_ID / OPENEO_CLIENT_SECRET (headless) or sign in once\n"
"interactively (see the Authentication page) to run this cell for real."
)
return []
paths = facade.download(**download_kwargs)
for path in paths:
print(path)
return paths
Build the request¶
Construct the EarthLens facade for the sentinel-5p-no2-monthly recipe over the Benelux box and one month, then confirm which openEO collection it resolves to.
facade = EarthLens(
data_source='openeo',
dataset='sentinel-5p-no2-monthly',
variables=[],
start='2023-03-01',
end='2023-03-31',
aoi=[3.0, 50.5, 7.0, 53.5],
path='data/openeo-no2',
)
print('returns:', facade.datasource._resolved['sentinel-5p-no2-monthly'].collection_id)
Download (server-side execution)¶
Trigger the server-side monthly-mean reduction and download the resulting NetCDF. With no credentials this prints a skip note and returns an empty list.
paths = run_or_skip(facade)
paths