API reference

Auto-generated from docstrings.

Client

class sjvair.client.SJVAirClient(base_url: str | None = None, timeout: int | None = None, max_retries: int | None = None, max_connections: int | None = None, api_key: str | None = None)

HTTP client for the SJVAir API.

All resource objects (monitors, regions, calenviroscreen5, calenviroscreen4, ceidars, hms, pesticides, calheatscore, forecasts, tempo) are attached as attributes and share this client’s session, retry logic, and cooldown gate.

Parameters:
  • base_url – API base URL. Defaults to SJVAIR_BASE_URL env var or the production URL.

  • timeout – Request timeout in seconds. Defaults to SJVAIR_TIMEOUT env var or 30.

  • max_retries – Number of retries on 5xx / 429 responses. Defaults to 5.

  • max_connections – Maximum concurrent requests (semaphore). Defaults to 4.

  • api_key – Bearer token for authenticated endpoints. Defaults to SJVAIR_API_KEY env var.

Can be used as a context manager to ensure the underlying session is closed:

with SJVAirClient() as client:
    monitors = list(client.monitors.list())
get(path: str, params: dict[str, Any] | None = None) Any

GET path relative to base_url, with retry and cooldown.

Retries on 5xx and transient network errors (connection/timeout) up to max_retries times with exponential backoff. On 429, triggers a shared cooldown that blocks all threads until the wait expires. Raises NotFound on 404, RateLimited after exhausting retries on 429, ServerError after exhausting retries on 5xx or a persistent network error, and ClientError on other non-retryable 4xx responses.

Resources

class sjvair.resources.monitors.MonitorsResource(client: SJVAirClient)

Access air quality monitor data.

Available on SJVAirClient.monitors.

list(**params: Any) Iterator[dict[str, Any]]

Iterate all monitors, optionally filtered by region_id, is_sjvair, etc.

get(monitor_id: str) dict[str, Any]

Get a single monitor by ID.

meta() dict[str, Any]

Return field metadata for monitor entries (field names, units, etc.).

entries(monitor_id: str, entry_type: str, **params: Any) Iterator[dict[str, Any]]

Iterate paginated entries for one monitor and entry type (e.g. 'PM2.5').

export(monitor_id: str, start_date: str, end_date: str, scope: str = 'resolved') Iterator[dict[str, Any]]

Bulk-export entries for a monitor in a single request.

The server enforces a 180-day maximum window per call. Use ExportEngine to download longer ranges automatically by splitting into chunks.

Parameters:
  • monitor_id – Monitor UUID.

  • start_date – ISO 8601 date string (YYYY-MM-DD).

  • end_date – ISO 8601 date string (YYYY-MM-DD).

  • scope'resolved' (calibrated) or 'expanded' (raw + derived fields).

summaries(monitor_id: str, entry_type: str, resolution: str, start_date: str, end_date: str) Iterator[dict[str, Any]]

Iterate aggregated summaries for a monitor across the given date range.

Parameters:
  • monitor_id – Monitor UUID.

  • entry_type – Sensor field (e.g. 'PM2.5').

  • resolution – One of 'hourly', 'daily', 'monthly', 'quarterly', 'seasonal', 'yearly'.

  • start_date – ISO 8601 date string.

  • end_date – ISO 8601 date string.

closest(entry_type: str, lat: float, lon: float, **params: Any) list[dict[str, Any]]

Return up to 3 nearest active monitors with distance and latest entry.

Pass device to filter by device type (e.g. device='CIMIS').

current(entry_type: str, **params: Any) Iterator[dict[str, Any]]

Iterate all active monitors with their most recent entry for the given type.

Pass device to filter by device type (e.g. device='CIMIS').

current_at(entry_type: str, timestamp: str, region: list[str] | None = None, bbox: tuple[float, float, float, float] | None = None, **params: Any) Iterator[dict[str, Any]]

As current(), but as-of a historical timestamp (ISO 8601).

Parameters:
  • entry_type – Sensor field (e.g. 'pm25').

  • timestamp – ISO 8601 timestamp to query as-of.

  • region – One or more region IDs to filter to monitors covered by their boundaries.

  • bbox(west, south, east, north) to filter to monitors within the box.

Pass device to filter by device type (e.g. device='CIMIS').

class sjvair.resources.regions.RegionsResource(client: SJVAirClient)

Access geographic region data (counties, cities, ZIP codes, census tracts).

Available on SJVAirClient.regions.

list(**params: Any) Iterator[dict[str, Any]]

Iterate all regions, optionally filtered by kind, county, etc.

get(region_id: str) dict[str, Any]

Get a single region by ID.

search(query: str, **params: Any) list[dict[str, Any]]

Search regions by name, returning all high-confidence matches. Pass type= to scope to a specific region type.

lookup(query: str, **params: Any) dict[str, Any] | None

Resolve a name to the single best-match region. Pass type= to scope to a specific region type.

summaries(region_id: str, entry_type: str, resolution: str, start_date: str, end_date: str) Iterator[dict[str, Any]]

Iterate aggregated summaries for a region. Same resolution options as MonitorsResource.summaries().

class sjvair.resources.calenviroscreen.CalEnviroScreen5Resource(client: SJVAirClient)

Access CalEnviroScreen 5.0 census tract cumulative impact scores.

Available on SJVAirClient.calenviroscreen5.

list(**params: Any) Iterator[dict[str, Any]]

Iterate census tract scores.

Single-vintage dataset (2020 census tracts) — no year filter. Filters are applied server-side. Pass region_id to scope to a region, dac_sb535/dac_category for the disadvantaged-community designation, or __gt/__gte/__lt/__lte suffixes for threshold lookups on any score field.

get(tract: str) dict[str, Any]

Get CalEnviroScreen 5.0 scores for a single census tract (FIPS code).

class sjvair.resources.calenviroscreen.CalEnviroScreen4Resource(client: SJVAirClient)

Access CalEnviroScreen 4.0 census tract cumulative impact scores.

Available on SJVAirClient.calenviroscreen4.

list(year: int | None = None, **params: Any) Iterator[dict[str, Any]]

Iterate census tract scores.

year defaults server-side to 2020 if omitted. Filters are applied server-side. Pass region_id to scope to a region, dac_sb535/ dac_category for the disadvantaged-community designation, or __gt/__gte/__lt/__lte suffixes for threshold lookups on any score field (e.g. pollution_p__gte=75).

get(tract: str, year: int | None = None) dict[str, Any]

Get CalEnviroScreen 4.0 scores for a single census tract (FIPS code).

year defaults server-side to 2020 if omitted.

class sjvair.resources.ceidars.CEIDARSResource(client: SJVAirClient)

Access CEIDARS (California Emissions Inventory) facility data.

Available on SJVAirClient.ceidars.

list(**params: Any) Iterator[dict[str, Any]]

Iterate all CEIDARS facilities.

get(facility_id: str) dict[str, Any]

Get a single CEIDARS facility by ID.

years() list[int]

Return the list of inventory years available in the dataset.

class sjvair.resources.hms.HMSResource(client: Any)

Access NOAA Hazard Mapping System (HMS) smoke and fire data.

Available on SJVAirClient.hms. Sub-resources:

  • smoke — smoke plume polygons

  • fire — fire detection points

class sjvair.resources.pesticides.PesticidesResource(client: Any)

Access California Department of Pesticide Regulation (CDPR) pesticide data.

Available on SJVAirClient.pesticides. Sub-resources:

  • chemicals — active ingredient lookup

  • commodities — crop/commodity lookup

  • products — registered product lookup

  • use — pesticide use reports

  • notice — pesticide use notices

region_use(region_id: str, **params: Any) Iterator[dict[str, Any]]

Iterate pesticide use reports for a specific region.

region_notice(region_id: str, **params: Any) Iterator[dict[str, Any]]

Iterate pesticide use notices for a specific region.

region_summary(region_id: str) dict[str, Any]

Return an aggregate pesticide use summary for a region.

class sjvair.resources.calheatscore.CalHeatScoreResource(client: SJVAirClient)

Daily ZIP-code-level heat-risk scores (0-4) from CalEPA’s CalHeatScore.

Available on SJVAirClient.calheatscore.

list(**params: Any) Iterator[dict[str, Any]]

Iterate CalHeatScore rows across ZIP codes.

Defaults to today (server-side) if no date filter is given. Filters: date/date__gte/date__lte, score/score__gte/score__lte, zipcode, zipcode__in (comma-separated).

zipcode(zipcode: str, **params: Any) Iterator[dict[str, Any]]

Iterate all stored CalHeatScore rows (history + forecast) for one ZIP code, newest first.

Accepts the same date/score filters as list() to narrow the range.

class sjvair.resources.forecasts.ForecastsResource(client: SJVAirClient)

SJVAPCD daily air quality forecasts, by SJV county zone.

Available on SJVAirClient.forecasts.

list(**params: Any) Iterator[dict[str, Any]]

Iterate forecasts across zones.

Defaults to current + future forecasts (server-side, forecast_date >= today) if no forecast_date filter is given. Filters: region_id, forecast_date/forecast_date__lt/__lte/__gt/__gte, issued_date/issued_date__lt/__lte/__gt/__gte.

get(forecast_id: str) dict[str, Any]

Get a single forecast record by ID.

class sjvair.resources.tempo.TempoResource(client: SJVAirClient)

NASA TEMPO satellite air-quality data (NO2, O3TOT, HCHO, CLDO4 — hourly gridded column-density measurements).

Available on SJVAirClient.tempo.

products() list[dict[str, Any]]

List TEMPO product metadata: label, units, and legend color stops.

Excludes cldo4 (QA-only, not a toggleable map layer) — it’s still a valid product value for granules()/point()/region().

granules(product: str, **params: Any) Iterator[dict[str, Any]]

Iterate TEMPO granules for one product.

Defaults to today’s granules (America/Los_Angeles, falling back to yesterday if it’s before noon and today’s data isn’t ready) when no date/timestamp filter is given. Filters: date, timestamp/timestamp__lt/__lte/__gt/__gte, is_final, version/version__iexact.

latest(product: str) dict[str, Any]

Get the single most recent granule for one product.

point(product: str, latitude: float, longitude: float, start: str | None = None, end: str | None = None) list[dict[str, Any]]

Get an hourly point-value series for one product at a coordinate.

start/end are ISO 8601 timestamps; omit both to default to today’s available granules. Max range is 90 days.

region(product: str, region_id: str, start: str | None = None, end: str | None = None) list[dict[str, Any]]

Get an hourly zonal-stats series for one product over a region boundary.

Same start/end semantics as point().

Maps

Rendering utilities behind sjvair map/sjvair timelapse — requires pip install sjvair[maps] to actually render (importing the module does not).

Standalone static-map rendering for the sjvair map/sjvair timelapse commands.

Importing this module never requires the maps extra — only calling render_frame() does, so callers can defer that cost (and the import error, if the extra isn’t installed) until a map is actually being rendered.

sjvair.maps.color_for_value(levels: dict[str, Any], value: float) str

Pick a marker color for value from a meta() levels dict.

Linearly blends between the matched level and the next one, matching the server’s LevelSet.get_color().

value is coerced to float since the API serializes some monitors’ latest.value as a JSON string (server-side Decimal fields aren’t natively JSON-serializable) rather than a number.

sjvair.maps.shape_for_monitor(monitor: dict[str, Any]) str

Marker shape by monitor grade: triangle for regulatory (FEM/FRM) networks, circle for SJVAir low-cost sensors, square for other third-party monitors.

sjvair.maps.render_frame(monitors: list[dict[str, Any]], levels: dict[str, Any], outlines: list[dict[str, Any]], viewport: tuple[float, float, float, float], timestamp_label: str | None = None, show_legend: bool = True, legend_label: str | None = None, width: int = 1600, height: int = 1200, dpi: int = 100, marker_size: int = 220) bytes

Render one map frame to PNG bytes: basemap, region outlines, monitor markers colored by AQI level, and optional legend/timestamp overlays.