Skip to main content

Unofficial Python client for Weathercloud

Project description

weathercloud

PyPI Python CI License: MIT

Unofficial, fully-typed Python client for Weathercloud. Read live conditions, station metadata, history, and forecasts from any public station — no account, no API key.

⚠️ Reverse-engineered from the public web app. Not affiliated with or endorsed by Weathercloud, and the upstream endpoints may change without notice.

✨ Highlights

  • 🌡️ Typed resultsget_current_conditions() returns a CurrentConditions dataclass, not a bag of stringly-typed JSON.
  • 🧱 Raw access too — every endpoint also has a dict-returning method when you need the full payload.
  • 🧯 One exception to catch — every failure (network, HTTP, bad JSON) raises WeathercloudError.
  • 🧪 Tested & type-checked — ships py.typed, runs on Python 3.10–3.13.

📦 Installation

pip install weathercloud

🚀 Quick start

from weathercloud import WeathercloudClient

with WeathercloudClient() as client:
    cond = client.get_current_conditions("5726468552")

print(cond.temperature)   # 22.8
print(cond.humidity)      # 62
print(cond.wind_gust)     # 1.4

The client owns a requests.Session, so use it as a context manager (or call client.close()) to release connections. You can also tune the request timeout:

client = WeathercloudClient(timeout=30)   # seconds; default is 10

📖 API

get_current_conditions(device_id)CurrentConditions

Live sensor readings as a typed dataclass — the one you'll call most. Stations only report the sensors they actually have, so every field is optional: a reading the station doesn't provide comes back as None rather than raising.

Field Type Unit Field Type Unit
temperature float | None °C pressure float | None hPa
dew_point float | None °C wind_speed float | None m/s
wind_chill float | None °C wind_speed_avg float | None m/s
heat_index float | None °C wind_gust float | None m/s
humidity int | None % wind_direction int | None °
rain float | None mm rain_rate float | None mm/h
solar_radiation float | None W/m² uv_index int | None
epoch int | None unix ts

get_station_info(device_id, scrape_name=True)StationInfo

Station metadata. The name isn't exposed by any JSON endpoint, so it's scraped from the page <title> (one extra request). Pass scrape_name=False to skip it and use the device_id as the name instead.

info = client.get_station_info("5726468552")
info.name                   # "Ginometeo"
info.city                   # "Ingelmunster"
info.altitude               # "18.0"  (metres, as string)
info.status                 # "online" | "recently_online" | "offline" | "unknown"
info.seconds_since_update   # int
info.account_type           # 0 = free, >0 = premium

get_device_stats(device_id)dict

Current readings plus day / month / year min–max. Each value is a [unix_timestamp, value] pair, keyed as {sensor}_{period}_{type}.

stats = client.get_device_stats("5726468552")
stats["temp_day_max"]       # [1748358122, 30.9]
stats["rain_month_total"]   # [1748358122, 12.4]

get_evolution(device_id, variable, period="day")dict

Hourly history for a single sensor. period is "day", "week", "month", or "year".

from weathercloud import VariableCode

evo = client.get_evolution("5726468552", VariableCode.TEMPERATURE, "week")

Available codes: TEMPERATURE, HUMIDITY, DEW_POINT, PRESSURE, WIND_SPEED, WIND_DIRECTION, WIND_GUST, RAIN, RAIN_RATE, SOLAR_RADIATION, UV_INDEX.

get_forecast(device_id)dict

6-day WMO daily forecast for the station's location.

get_nearby_stations(lat, lon, distance_km=5)dict

Stations within a radius of a coordinate. ⚠️ Sensor values inside each result are ×10 integers — divide by 10 (e.g. temp: 281 → 28.1 °C).

Other raw methods

client.get_device_values(device_id)    # same data as get_current_conditions, raw
client.get_device_info(device_id)       # metadata + current values as strings
client.get_wind_rose(device_id)         # wind direction distribution
client.get_update_status(device_id)     # seconds since last update
client.get_owner_profile(device_id)     # observer name, hardware brand/model
client.get_station_name(device_id)      # scrape the station name only

🧯 Error handling

Every method raises WeathercloudError on failure — network error, HTTP error, non-JSON body, or an unexpected response shape. Catch the one type and you're covered.

from weathercloud import WeathercloudClient, WeathercloudError

try:
    cond = client.get_current_conditions(device_id)
except WeathercloudError as exc:
    ...  # set unavailable, log it, retry — your call

🔎 Finding a device ID

It's the number at the end of the station URL:

app.weathercloud.net/d5726468552  →  device_id = "5726468552"

METAR (airport) stations use ICAO codes (EBBR, EGLL, …) and work on most device/* endpoints — just swap the prefix to metar/*.

💡 Notes

  • 🔓 No authentication required for any endpoint.
  • ⏱️ Poll at most every 10 minutes — that's how often free stations update.
  • 🧭 Based on the reverse-engineered OpenAPI spec in this repo.

🛠️ Development

git clone https://github.com/MauroDruwel/Weathercloud-API
cd Weathercloud-API
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

ruff check .      # lint
mypy              # type-check
pytest            # tests
python -m build   # build sdist + wheel

CI runs the linter, type checker, and the test matrix (Python 3.10–3.13) on every push and pull request.

Local API explorer (Swagger UI)

A Swagger UI is hosted at weathercloud-api.maurodruwel.be, or run it locally against a small CORS proxy:

pip install flask
python docs/proxy.py   # serves the proxy + Swagger UI on :8765
# then open docs/index.html

📄 License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

weathercloud-0.1.1.tar.gz (14.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

weathercloud-0.1.1-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file weathercloud-0.1.1.tar.gz.

File metadata

  • Download URL: weathercloud-0.1.1.tar.gz
  • Upload date:
  • Size: 14.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for weathercloud-0.1.1.tar.gz
Algorithm Hash digest
SHA256 343d8ea4652be54d047c1cd128805c476c1c21c7feb538178c57a24d93e37da0
MD5 b2a8f4fbd4b022f51664838a806988af
BLAKE2b-256 a5abe2d94ad3de6ed2483c20864c93ebd67b319ec45bb2674ea3d652b0f4cbb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for weathercloud-0.1.1.tar.gz:

Publisher: publish.yml on MauroDruwel/Weathercloud

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file weathercloud-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: weathercloud-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for weathercloud-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 19651e4c132d992935a647d331f0c5161dc2923170c25bf36ab09edc87a278fe
MD5 d7af1e94c03d7a7cb736cfcef54c9a2d
BLAKE2b-256 3f6a8643e1f7f68ddeda6de7b593031098f99543bb5ca09ec8ce277968bf5017

See more details on using hashes here.

Provenance

The following attestation bundles were made for weathercloud-0.1.1-py3-none-any.whl:

Publisher: publish.yml on MauroDruwel/Weathercloud

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page