Metadata-Version: 2.4
Name: MeteoGalicia-API
Version: 0.1.10
Summary: Python client for the MeteoGalicia weather and tide services
Author-email: danieldiazi <dandiazde@gmail.com>
License-Expression: GPL-3.0-only
Project-URL: Homepage, https://github.com/Danieldiazi/meteogalicia-api
Project-URL: Issues, https://github.com/Danieldiazi/meteogalicia-api/issues
Keywords: MeteoGalicia
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: requests
Requires-Dist: xmltodict
Requires-Dist: tzdata
Dynamic: license-file


![PyPI](https://img.shields.io/pypi/v/MeteoGalicia-API)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/MeteoGalicia-API)

Description
-----------

MeteoGalicia-API implements an interface to the MeteoGalicia Rest web services.

Documentation about MeteoGalicia web service is available at https://www.meteogalicia.gal/web/RSS/rssIndex.action?request_locale=es.

This package has been developed to be used with  [homeassistant-meteogalicia](https://github.com/Danieldiazi/homeassistant-meteogalicia)  integration for [Home-Assistant](https://home-assistant.io/)

Disclaimer
----------

This software is provided without warranty, and should therefore not be used where it may endanger life, financial stakes, or cause discomfort and inconvenience to others. Is also licensed under the GNU Public Licence version 3

Usage
-----

Example:
```python
from meteogalicia_api.interface import MeteoGalicia
meteogalicia = MeteoGalicia()
meteogalicia.get_forecast_data("32054")
meteogalicia.get_observation_data("15023")
```

Custom session and timeout:

```python
import requests
from meteogalicia_api.interface import MeteoGalicia

session = requests.Session()
meteogalicia = MeteoGalicia(session=session, timeout=10)
meteogalicia.get_forecast_data("32054")
```

Tide forecasts are dated in Europe/Madrid, including when the caller runs in
another timezone. The date field describes today's RSS item; todayDate,
tomorrowDate and yesterdayDate are local calendar dates in ISO format.
The tomorrowTides field contains all tides for tomorrow, while
tomorrowFirstTide remains available. RSS items are selected by forecast date
rather than their order in the response.
Timezone rules fall back to the packaged tzdata when the host has no IANA database.

Town hall or city data methods:
```python
meteogalicia.get_forecast_data("32054")
meteogalicia.get_hourly_forecast_data("32054")
meteogalicia.get_medium_term_forecast_data("32054")
meteogalicia.get_warnings_data("32054")
meteogalicia.get_max_warning_levels_data("32054")
meteogalicia.get_observation_data("15023")
```
Parameter id's are available at https://www.meteogalicia.gal/datosred/infoweb/meteo/docs/rss/JSON_Pred_Concello_es.pdf 

Hourly and medium term forecasts:

Both methods return the original JSON dictionary, including the forecast wrapper.
They return `None` if the request fails, the forecast container is missing or is
not an object, or its prediction list is missing, empty or is not a list. Individual
records are returned unchanged; the client does not validate every field.

| Method | Prediction list in the returned dictionary | Main fields |
| --- | --- | --- |
| `get_hourly_forecast_data(id)` | `data["predHoraria"]["listaPredDiaHoraria"]` | Each day contains `dia` and `listaPredHora`; each hour contains `dataPredicion`, `tMedia`, `icoCeo` and `icoVento`. |
| `get_medium_term_forecast_data(id)` | `data["predMPrazo"]["listaPredDiaMPrazo"]` | Each day contains `dataPredicion`, `dia`, `tMin`, `tMax`, sky condition alternatives and their probabilities. |

- Hourly `dataPredicion` values use local time in Galicia (`Europe/Madrid`) and
  contain no UTC offset. The client does not convert them to UTC. Consumers must
  account for the local time zone and daylight saving changes.
- MeteoGalicia uses `-9999` for unavailable weather values. The client preserves
  this sentinel; consumers should treat it as missing data, not as a temperature,
  probability or valid weather code.
- Medium term `icoCeo1`, `icoCeo2` and `icoCeo3` are possible sky conditions with
  corresponding `probIcoCeo1`, `probIcoCeo2` and `probIcoCeo3` probabilities. They
  are not morning, afternoon and night forecasts. Use the probabilities when
  choosing a representative condition.
- The medium term forecast starts after the short term forecast. The number of
  days and hours varies with availability; combine daily forecasts using their
  dates rather than assuming fixed list lengths.

```python
data = meteogalicia.get_hourly_forecast_data("15030")
if data is not None:
    for day in data["predHoraria"]["listaPredDiaHoraria"]:
        for hour in day["listaPredHora"]:
            temperature = hour.get("tMedia")
            if temperature is not None and temperature != -9999:
                print(hour["dataPredicion"], temperature)
```

Official response schemas and weather codes:
[hourly forecast](https://www.meteogalicia.gal/datosred/infoweb/meteo/docs/rss/JSON_Pred_Horaria_Concello_es.pdf)
and [medium term forecast](https://www.meteogalicia.gal/datosred/infoweb/meteo/docs/rss/JSON_Pred_MPrazo_es.pdf).

Warning methods:

```python
# Detailed warnings: level, alert type and validity period.
warnings = meteogalicia.get_warnings_data("15030", day=-1)

# MeteoGalicia's own maximum warning level summary.
levels = meteogalicia.get_max_warning_levels_data("15030", day=-1)
```

The optional `day` argument accepts `0` (today), `1` (tomorrow), `2`
(the day after tomorrow) and `-1` (all available days). Both methods return
the original MeteoGalicia JSON dictionary. In both endpoints, including requests
for a single day, `listaDiaConcellos` contains day objects with a `dia` field and
either `listaAvisosConcellos` or `listaNiveisMaximos`. Select days by `dia`, not
their position in the list.

```python
if warnings is not None:
    for daily in warnings["listaDiaConcellos"]:
        print(daily["dia"], daily["listaAvisosConcellos"])
```

An empty daily list is a valid response: for detailed warnings it means there
are no warnings for that day. Malformed responses and request failures return
`None`.

- `get_warnings_data()` uses `jsonAvisosConcellos.action` and exposes individual
  warnings, including `idNivel`, `dataAviso`, `dataIni`, `dataFin`,
  `idTipoAlerta`, `tipoalerta_gl` and `tipoalerta_es`.
- `get_max_warning_levels_data()` uses `jsonConcellosNivelMax.action` and exposes
  MeteoGalicia's `nivelMax` summary (0 normal, 1 yellow, 2 orange, 3 red).

Official documentation:
[complete municipal warnings](https://meteo-estaticos.xunta.gal/datosred/infoweb/meteo/docs/rss/JSON_Pred_AvisoConcello_gl.pdf)
and [maximum municipal warning level](https://meteo-estaticos.xunta.gal/datosred/infoweb/meteo/docs/rss/JSON_Pred_AvisoConcelloNivelMax_gl.pdf).

Configuration catalogs:

```python
# Static municipal catalog, optionally filtered by province.
concellos = meteogalicia.get_concellos("A Coruña")

# Live MeteoGalicia station catalog, optionally filtered by province/concello.
stations = meteogalicia.get_stations(
    province="A Coruña",
    concello="Santiago de Compostela",
)
```

`get_concellos()` returns dictionaries containing `idConcello`, `concello` and
`provincia`. Municipal identifiers are maintained as a static catalog because
they are effectively stable and are used by forecast and warning services.

`get_stations()` reads MeteoGalicia's current station catalog and returns the
original station dictionaries, optionally filtered by province and concello.
Station identifiers (`idEstacion`) are separate from municipal identifiers
(`idConcello`); callers should not interchange them.

Station methods:
```python
meteogalicia.get_observation_dailydata_by_station("10144")
meteogalicia.get_observation_last10mindata_by_station("10144")
```
Parameter station id's and the live station catalog are available at
https://servizos.meteogalicia.gal/mgrss/observacion/listaEstacionsMeteo.action?request_locale=gl

Tides methods:

```python
meteogalicia.get_forecast_tide("3")
```
id availables at: https://www.meteogalicia.gal/datosred/infoweb/meteo/docs/rss/RSS_Mareas_gl.pdf

Errors:

Methods return `None` by default when a request fails or no data is available.
The `last_error` attribute describes the most recent failure and is cleared by
the next successful request. Enable `raise_on_error=True` to handle typed errors:

```python
from meteogalicia_api.errors import MeteoGaliciaError
from meteogalicia_api.interface import MeteoGalicia

client = MeteoGalicia(timeout=10, raise_on_error=True)
try:
    forecast = client.get_forecast_data("15030")
except MeteoGaliciaError as error:
    print(error.kind, error.retryable, error.retry_after)
```

Error types distinguish connection failures, timeouts, HTTP status errors,
invalid responses and missing data. HTTP errors expose `status_code`. A valid
`Retry-After` header on HTTP 429 or 5xx responses is returned in seconds. The
client does not retry automatically; callers can choose their own retry policy.

Publishing
----------

After merging a version change, push a branch named `publish/v<VERSION>` at
the merged commit. The publication workflow tests and validates distributions,
checks the version, publishes to PyPI using Trusted Publishing, and creates the
GitHub release only after PyPI succeeds. Publishing an existing release remains
supported.

