# Mareator API — Manual de uso

API REST para predicción de mareas, condiciones del mar y meteorología costera.
Todas las respuestas son **JSON UTF-8**, siempre con la misma estructura base.

---

## URL base

```
http://<servidor>/mareator2/codigo/api/
```

Ejemplo si el servidor es `surf.local`:
```
http://surf.local/mareator2/codigo/api/mareas?loc=1&dias=3
```

---

## Estructura de respuesta

Todos los endpoints devuelven el mismo esqueleto JSON:

```json
{
  "ok": true,
  "endpoint": "/api/mareas",
  "url_solicitada": "http://servidor/api/mareas?loc=1&dias=3",
  "timestamp_solicitud": "2026-03-24T10:30:00+01:00",
  "parametros": { "loc": 1, "fecha": "2026-03-24", "dias": 3 },
  "localizacion": {
    "id": 1,
    "nombre": "Coruña",
    "lat": 43.3781,
    "lon": -8.393,
    "puerto_id": "20"
  },
  "fechas": {
    "inicio": "2026-03-24",
    "fin": "2026-03-26",
    "dias": 3,
    "rango": ["2026-03-24", "2026-03-25", "2026-03-26"]
  },
  "datos": { ... },
  "error": null
}
```

### Respuesta de error

```json
{
  "ok": false,
  "endpoint": "/api/mareas",
  "url_solicitada": "http://servidor/api/mareas?loc=99",
  "timestamp_solicitud": "2026-03-24T10:30:00+01:00",
  "parametros": { "loc": "99" },
  "localizacion": null,
  "fechas": null,
  "datos": null,
  "error": {
    "codigo": "LOC_INVALIDA",
    "mensaje": "Localización '99' no existe. Valores válidos: 1–6.",
    "detalle": "Consulta /api para ver la lista de localizaciones."
  }
}
```

---

## Parámetros comunes

| Parámetro | Tipo   | Defecto   | Descripción |
|-----------|--------|-----------|-------------|
| `loc`     | int    | —         | ID de localización predefinida (1–6). Aporta lat, lon y puerto_id. |
| `lat`     | float  | —         | Latitud decimal (−90 a 90). Alternativa a `loc`. |
| `lon`     | float  | —         | Longitud decimal (−180 a 180). Alternativa a `loc`. |
| `fecha`   | string | hoy       | Fecha de inicio en formato `YYYY-MM-DD`. Admite pasado y futuro. |
| `dias`    | int    | varía     | Número de días a consultar (mínimo 1). |

**Regla:** usa `loc` **o** `lat`+`lon`. No se pueden mezclar.

---

## Localizaciones predefinidas

| ID | Nombre     | Lat      | Lon      | Puerto IHM |
|----|------------|----------|----------|------------|
| 1  | Coruña     | 43.3781  | −8.3930  | 20         |
| 2  | Miño       | 43.3521  | −8.2220  | 19         |
| 3  | Doniños    | 43.4969  | −8.3240  | 18         |
| 4  | O Grove    | 42.4563  | −8.9219  | 27         |
| 5  | Area Maior | 42.7512  | −9.0978  | 24         |
| 6  | Deltebre   | 40.7181  | +0.7217  | 50         |

Consulta la lista completa con sus coordenadas en: `GET /api`

---

## Endpoints

---

### `GET /api/mareas`

Predicción de mareas. Devuelve los extremos (pleamar/bajamar) en el rango de fechas pedido,
más la altura instantánea y el estado actual del ciclo de marea si el rango incluye el momento presente.

**Fuente por defecto:** motor armónico autónomo basado en constituyentes TICON-3 (Hart-Davis et al. 2022).
Predicción completamente local, ilimitada en el tiempo, sin dependencia de APIs externas.

**Parámetros específicos:**

| Parámetro | Tipo   | Defecto      | Límites | Descripción |
|-----------|--------|--------------|---------|-------------|
| `loc`     | int    | —            | 1–6     | Localización predefinida (incluye puerto_id) |
| `puerto`  | string | —            | 18–50   | ID de puerto IHM directo (alternativa a `loc`) |
| `fecha`   | string | hoy          | —       | Fecha de inicio |
| `dias`    | int    | **7**        | 1–30    | Días a calcular |
| `fuente`  | string | `armonico`   | `armonico` \| `ihm` | Motor a usar (ver abajo) |

**Parámetro `fuente`:**
- `armonico` (defecto): motor armónico autónomo TICON-3. Ilimitado en tiempo, sin red.
- `ihm`: API oficial del Instituto Hidrográfico de la Marina. Cobertura ~30 días atrás y ~1 año adelante. Requiere conectividad con `ideihm.covam.es`.

> **Nota:** Las mareas solo están disponibles para puertos con datos armónicos:
> 18, 19, 20, 24, 27, 50. Para cualquier otro puerto se devuelve error.

**Ejemplo — próximos 7 días en Coruña:**
```
GET /api/mareas?loc=1
```

**Ejemplo — semana pasada en O Grove:**
```
GET /api/mareas?loc=4&fecha=2026-03-17&dias=7
```

**Ejemplo — un día concreto con puerto directo:**
```
GET /api/mareas?puerto=20&fecha=2026-06-21
```

**Ejemplo — datos del IHM para los próximos 3 días:**
```
GET /api/mareas?loc=1&fuente=ihm&dias=3
```

**Estructura de `datos` (fuente `armonico`):**
```json
{
  "fuente": "Armónico autónomo TICON-3",
  "puerto": "A Coruña",
  "Z0_m": 2.1,
  "extremos": [
    {
      "tipo": "pleamar",
      "altura_m": 3.84,
      "timestamp_utc": "2026-03-24T07:23:00+00:00",
      "timestamp_local": "2026-03-24T08:23:00+01:00",
      "fecha": "2026-03-24",
      "hora_local": "08:23",
      "t_total": 8.383
    },
    {
      "tipo": "bajamar",
      "altura_m": 0.52,
      "t_total": 14.712,
      ...
    }
  ],
  "total_extremos": 28,
  "altura_actual_m": 2.14,
  "siguiente_extremo": { "tipo": "pleamar", "hora_local": "08:23", "altura_m": 3.84, ... },
  "punto_marea_actual": {
    "idx": 3.2,
    "pct": 53.3,
    "subiendo": true,
    "extremo_previo":    { "tipo": "bajamar",  "hora_local": "03:15", "altura_m": 0.52, ... },
    "extremo_siguiente": { "tipo": "pleamar",  "hora_local": "08:23", "altura_m": 3.84, ... },
    "mins_para_siguiente": 135,
    "tiempo_para_siguiente": "2h 15min"
  }
}
```

> `altura_actual_m`, `siguiente_extremo` y `punto_marea_actual` solo aparecen (no nulos) cuando
> el rango solicitado incluye el momento presente. Si el rango es futuro o pasado, valen `null`.

**Campo `t_total`:** horas transcurridas desde medianoche (hora de Madrid) del primer día del rango.
Sirve como escala temporal común para todos los extremos del mismo rango.

**Campo `punto_marea_actual`:** aproximación coseno (regla de los doceavos) del estado del ciclo de marea.
- `idx`: índice 0–6 (0 = bajamar exacta, 6 = pleamar exacta, 3 = punto medio del flujo).
- `pct`: porcentaje equivalente (0–100 %).
- `subiendo`: `true` si la marea está subiendo, `false` si está bajando.
- `tiempo_para_siguiente`: tiempo hasta el siguiente extremo en formato legible (`"2h 15min"`).

**Estructura de `datos` (fuente `ihm`):** igual que la anterior excepto que no incluye `Z0_m`
y `altura_actual_m` (el IHM no proporciona altura continua, solo extremos).

---

### `GET /api/temperatura-agua`

Temperatura del agua del mar hora a hora.
**Fuente:** MeteoGalicia ROMS (modelo oceánico regional).
**Horizonte:** ~5 días hacia el futuro desde el momento de consulta.
**Histórico:** No disponible (se devuelve error con explicación).

**Parámetros específicos:**

| Parámetro | Defecto | Límites | Descripción |
|-----------|---------|---------|-------------|
| `fecha`   | hoy     | ahora…+5d | Fecha de inicio |
| `dias`    | 1       | 1–5     | Días a consultar |

> **Nota sobre cobertura ROMS:** el modelo solo cubre puntos de **mar abierto**.
> Las coordenadas de consulta se desplazan automáticamente 2 km al NO respecto a las coordenadas indicadas,
> para alejarse de la costa y mejorar la cobertura del modelo.
> Si aun así obtienes error `SIN_DATOS_ROMS`, prueba con coordenadas más alejadas de la costa.

**Ejemplo — temperatura hoy en Doniños:**
```
GET /api/temperatura-agua?loc=3
```

**Ejemplo — próximos 3 días con coordenadas personalizadas:**
```
GET /api/temperatura-agua?lat=43.5&lon=-8.1&dias=3
```

**Estructura de `datos`:**
```json
{
  "fuente": "MeteoGalicia ROMS",
  "aviso": null,
  "horario": [
    {
      "timestamp_utc": "2026-03-24T07:00:00+00:00",
      "timestamp_local": "2026-03-24T08:00:00+01:00",
      "fecha": "2026-03-24",
      "hora_local": "08:00",
      "temperatura_agua_c": 14.5,
      "descripcion": "Fría"
    }
  ],
  "total_horas": 24,
  "resumen": {
    "minima_c": 13.8,
    "maxima_c": 15.1,
    "media_c": 14.4
  }
}
```

**Escala de descripción de temperatura:**
| Rango     | Descripción |
|-----------|-------------|
| < 10 °C   | Muy fría    |
| 10–15 °C  | Fría        |
| 15–20 °C  | Fresca      |
| 20–25 °C  | Agradable   |
| ≥ 25 °C   | Cálida      |

---

### `GET /api/mar`

Condiciones del mar hora a hora: altura de ola, dirección y período.
**Fuente:** Open-Meteo Marine API.
**Histórico:** Sí (el mismo endpoint soporta fechas pasadas con `start_date`/`end_date`).

**Parámetros específicos:**

| Parámetro | Defecto | Límites | Descripción |
|-----------|---------|---------|-------------|
| `fecha`   | hoy     | cualquier fecha | Fecha de inicio |
| `dias`    | 1       | 1–7     | Días a consultar |

**Ejemplo — condiciones de hoy en Coruña:**
```
GET /api/mar?loc=1
```

**Ejemplo — semana completa:**
```
GET /api/mar?loc=1&dias=7
```

**Ejemplo — datos históricos:**
```
GET /api/mar?lat=43.3781&lon=-8.393&fecha=2024-12-25&dias=3
```

**Estructura de `datos`:**
```json
{
  "fuente": "Open-Meteo Marine",
  "horario": [
    {
      "timestamp_local": "2026-03-24T01:00:00+01:00",
      "fecha": "2026-03-24",
      "hora_local": "01:00",
      "altura_ola_m": 1.2,
      "direccion_deg": 285,
      "direccion_texto": "O",
      "periodo_s": 8.3
    }
  ],
  "total_horas": 24,
  "resumen": {
    "altura_min_m": 0.8,
    "altura_max_m": 2.1,
    "altura_media_m": 1.4
  }
}
```

---

### `GET /api/tiempo`

Previsión meteorológica hora a hora: temperatura, viento, lluvia, nubosidad.
**Fuente previsión:** Open-Meteo Forecast (hasta ~16 días).
**Fuente histórico:** Open-Meteo ERA5 Archive (para fechas > 90 días atrás).

**Parámetros específicos:**

| Parámetro | Defecto | Límites | Descripción |
|-----------|---------|---------|-------------|
| `fecha`   | hoy     | cualquier fecha | Fecha de inicio |
| `dias`    | 1       | 1–16    | Días a consultar |

**Ejemplo — previsión de hoy:**
```
GET /api/tiempo?loc=1
```

**Ejemplo — próximos 5 días:**
```
GET /api/tiempo?loc=4&dias=5
```

**Ejemplo — datos históricos hace 1 año:**
```
GET /api/tiempo?lat=43.3781&lon=-8.393&fecha=2025-03-24&dias=1
```

**Estructura de `datos`:**
```json
{
  "fuente": "Open-Meteo Forecast",
  "horario": [
    {
      "timestamp_local": "2026-03-24T01:00:00+01:00",
      "fecha": "2026-03-24",
      "hora_local": "01:00",
      "temperatura_c": 14.2,
      "lluvia_mm": 0.0,
      "nubosidad_pct": 45,
      "viento_kmh": 22.5,
      "direccion_viento_deg": 270,
      "direccion_viento_texto": "O",
      "codigo_wmo": 2,
      "descripcion_tiempo": "Parcialmente nublado",
      "prob_lluvia_pct": 5,
      "es_dia": true
    }
  ],
  "total_horas": 24,
  "resumen": {
    "temp_min_c": 12.1,
    "temp_max_c": 18.7,
    "viento_max_kmh": 35.0
  }
}
```

> **Nota:** `prob_lluvia_pct` y `es_dia` solo están presentes en previsión (no en datos históricos ERA5).

**Códigos WMO más comunes:**
| Código | Descripción          |
|--------|----------------------|
| 0      | Despejado            |
| 1      | Principalmente despejado |
| 2      | Parcialmente nublado |
| 3      | Nublado              |
| 45/48  | Niebla               |
| 51–55  | Llovizna             |
| 61–65  | Lluvia               |
| 71–75  | Nieve                |
| 80–82  | Chubascos            |
| 95     | Tormenta             |

---

## Códigos de error

| Código                          | HTTP | Causa |
|---------------------------------|------|-------|
| `PARAMETRO_OBLIGATORIO`         | 400  | Falta `loc` o `lat`/`lon` (o `puerto` en mareas) |
| `LOC_INVALIDA`                  | 400  | `loc` no está entre 1–6 |
| `COORDENADAS_INVALIDAS`         | 400  | `lat` o `lon` fuera de rango |
| `FECHA_INVALIDA`                | 400  | Formato de fecha incorrecto |
| `FECHA_FUERA_DE_HORIZONTE`      | 400  | Fecha más allá del límite del modelo |
| `FUENTE_INVALIDA`               | 400  | Valor de `fuente` desconocido |
| `PUERTO_NO_ENCONTRADO`          | 400  | No hay datos armónicos para el puerto indicado |
| `DATOS_HISTORICOS_NO_DISPONIBLES` | 400 | Se piden datos pasados donde no hay fuente disponible |
| `SIN_DATOS_ROMS`                | 400  | MeteoGalicia ROMS no tiene cobertura para esas coordenadas (zona costera o interior) |
| `ERROR_FUENTE_EXTERNA`          | 502  | Fallo de red al conectar con la fuente externa |
| `ERROR_API_METEOGALICIA`        | 502  | Error devuelto por la API de MeteoGalicia |
| `ERROR_API_IHM`                 | 502  | La API IHM no devolvió datos (fecha fuera de rango o puerto inválido) |
| `ERROR_API_OPENMETEO`           | 502  | Error devuelto por la API de Open-Meteo |
| `ENDPOINT_NO_ENCONTRADO`        | 404  | La ruta solicitada no existe |

---

## Casos de uso típicos

### "¿En qué punto del ciclo de marea estoy ahora?"
```
GET /api/mareas?loc=1&dias=2
```
→ Lee `datos.punto_marea_actual.idx` (0–6), `subiendo` y `tiempo_para_siguiente`.

### "¿Cuándo es la pleamar más cercana?"
```
GET /api/mareas?loc=1&dias=1
```
→ Mira `datos.siguiente_extremo` cuando `tipo == "pleamar"`.

### "¿Cómo está el mar ahora mismo?"
```
GET /api/mar?loc=1&dias=1
```
→ Filtra en `datos.horario` la hora más próxima al momento actual.

### "¿Cómo estaba el tiempo el día de Navidad de 2024?"
```
GET /api/tiempo?loc=1&fecha=2024-12-25&dias=1
```
→ Devolverá datos de ERA5 (reanalysis).

### "Planificar un surf trip la semana que viene"
```
GET /api/mar?loc=1&fecha=2026-03-31&dias=7
GET /api/tiempo?loc=1&fecha=2026-03-31&dias=7
GET /api/mareas?loc=1&fecha=2026-03-31&dias=7
```
→ Tres llamadas paralelas; correlacionar por `fecha` + `hora_local`.

### "Temperatura actual del agua en O Grove"
```
GET /api/temperatura-agua?loc=4&dias=1
```
→ Primer registro de `datos.horario` corresponde a la hora más reciente disponible.

### "Condiciones en un punto personalizado (coordenadas GPS)"
```
GET /api/mar?lat=43.5200&lon=-8.6700&dias=2
GET /api/tiempo?lat=43.5200&lon=-8.6700&dias=2
```

---

## Notas técnicas

- **Zona horaria:** todos los `timestamp_local` y `hora_local` son en hora de **Madrid** (CET/CEST, UTC+1/UTC+2).
- **Mareas:** predicción completamente autónoma, sin depender de APIs externas. Precisa ~30 s en los extremos.
- **`punto_marea_actual`:** solo está disponible cuando el rango solicitado incluye el instante presente. Para garantizarlo en cualquier hora del día, pide al menos desde el día anterior (`fecha=ayer&dias=3`), de modo que siempre exista un extremo previo al momento actual.
- **Temperatura del agua:** MeteoGalicia no ofrece datos históricos. Solo funciona para fechas presentes y futuras (≤ 5 días). El modelo ROMS solo cubre puntos de mar abierto.
- **Mar histórico:** Open-Meteo Marine guarda archivo histórico sin límite en el pasado.
- **Tiempo histórico:** para fechas > 90 días atrás se usa ERA5 (no incluye `prob_lluvia_pct` ni `es_dia`).
- **CORS:** La API responde con `Access-Control-Allow-Origin: *`, es accesible desde cualquier frontend.
- **Caché:** Las respuestas no se cachean (`Cache-Control: no-cache`). Implementa caché en el cliente si necesitas eficiencia.

---

## Fuentes de datos

| Datos                | Fuente                         | Cobertura temporal |
|----------------------|--------------------------------|--------------------|
| Mareas (armónico)    | TICON-3 (Hart-Davis et al. 2022, PANGAEA) | Ilimitada |
| Mareas (IHM)         | Instituto Hidrográfico de la Marina | ~30 días pasado + ~1 año futuro |
| Temperatura del agua | MeteoGalicia ROMS              | Próximos ~5 días   |
| Oleaje               | Open-Meteo Marine              | Histórico + 7 días |
| Meteorología         | Open-Meteo Forecast / ERA5     | Histórico + 16 días |
