Skip to main content

esios-complete

Conocimiento completo de ESIOS/REE: API, indicadores, unidades, deploy en NaN, troubleshooting frontend, informes Telegram, Open-Meteo, Yahoo Finance. Unificado de 5 skills en 1.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
Ntizar/MasterMind
آخر نشاط في المصدر
٤ سبتمبر ٢٠٢٦ في ١٠:٢٧
لغة SKILL.md المكتشفة
الإسبانية
النجوم
٢
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
8 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
esios-complete
description
Conocimiento completo de ESIOS/REE: API, indicadores, unidades, deploy en NaN, troubleshooting frontend, informes Telegram, Open-Meteo, Yahoo Finance. Unificado de 5 skills en 1.
version
1.1.0
author
Mastermind
tags
["esios","ree","energía","electricidad","deploy","telegram","api","nan"]
# ESIOS/REE — Conocimiento Completo **Unificado de 5 skills:** esios-api, esios-indicators-correct, esios-nan-deploy, esios-dashboard-troubleshooting, esios-telegram-report ## Tabla de Contenido 1. [API ESIOS](#1-api-esios) — Endpoints, autenticación, parsing, pitfalls 2. [Indicadores y Unidades](#2-indicadores-y-unidades) — IDs correctos, reglas de conversión 3. [Deploy en NaN.builders](#3-deploy-en-nanbuilders) — Dockerfile, Kaniko, variables, troubleshooting 4. [Dashboard Frontend Troubleshooting](#4-dashboard-frontend-troubleshooting) — Problemas comunes y soluciones 5. [Informe Telegram](#5-informe-telegram) — Script esios-telegram.js, gráficos Canvas 6. [Datos Externos](#6-datos-externos) — Open-Meteo (clima) y Yahoo Finance (gas/CO2) --- ## 1. API ESIOS **Base URL:** `https://api.esios.ree.es` **Autenticación:** Header `x-api-key: <token>` ### Formato de respuesta ```json { "indicator": { "values": [ { "value": 123.45, "datetime": "2026-05-25T00:00:00.000+02:00" } ] } } ``` ### 🔥 REGLA CRÍTICA: Sin time_trunc=hour **time_trunc=hour SUMA los 12 valores de 5 minutos, NO los promedia.** **Solución:** Sin truncar → datos cada 5 min (288 slots/día) → promediar los 12 valores de cada hora con `convertEsiosValue()`. ### 🔥 Auth variable por indicador NO todos los indicadores requieren token. Algunos funcionan sin auth: | Indicador | Sin auth | Con auth | |---|---|---| | 1001 (PVPC) | ✅ 120 values | ✅ | | 600 (Pool OMIE) | ✅ 288 values | ✅ | | 1293 (Demanda real) | ❌ 403 | ✅ | | 1294 (Renovables) | ❌ 403 | ✅ | | 2052 (Demanda prevista) | ❌ 403 | ✅ | **Diagnóstico rápido:** ```bash curl -s "https://api.esios.ree.es/indicators/ID" -H "Accept: application/json" | python3 -c " import json,sys; d=json.load(sys.stdin) if 'Status' in d: print(f'AUTH REQUIRED: {d[\"Status\"]}') else: print(f'OK: {len(d.get(\"indicator\",{}).get(\"values\",[]))} values') " ``` ### Endpoints del dashboard - `/api/esios/summary` — 24 slots horarios (promedio de 5 min) - `/api/esios/summary-5min` — 288 slots de 5 min sin colapsar ### Pitfalls - **PVPC (ID 1001):** 120 valores/día (24h × 5 geo zonas). Filtrar por `geo_id=8741` (Península) - **ID 9 (Ciclo Combinado):** Solo 1 valor diario, no 24 horarios - **Destructuring en Promise.all:** Verificar que el número de variables coincide EXACTAMENTE con N elementos - **Cache del navegador:** Cambios en JS no se reflejan. Usar `/js/cache-bust.js` --- ## 2. Indicadores y Unidades ### 🔥 Fuente de verdad: `convertEsiosValue()` **NUNCA asumir unidades por nombre de indicador.** Usar siempre la función `convertEsiosValue(indicatorId, rawValue)` del dashboard. ```javascript const DIRECT_IDS = new Set([ 1001, // PVPC €/MWh (filtrar por geo_id=8741 Península) 600, // Pool OMIE €/MWh 1293, // Demanda real (MW) 2052, // Demanda prevista (MW) 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2065, 2066, 2067, // Telemedida nacional (MW) 10351, 10352, // Gen real renovable/no renovable (MW) 10206, // Gen real Solar (MW) 10006, // Gen libre CO2 (MW) 10232, // Potencia disponible (MW) 2198, 2199, // Batería entrega/carga (MW) 1777, 1778, 1779, 1780, // Previsión D+1 (MW) 10358, 10359, // Previsión renovable D+1 (MW) 10355, 10356, // CO2 ratio (tCO₂/MWh, tCO₂/h) 10207, 10208, 10209, // Interconexiones (MW) ]); function convertEsiosValue(indicatorId, rawValue) { if (rawValue === null || rawValue === undefined) return null; const num = Number(rawValue); if (!Number.isFinite(num)) return null; if (DIRECT_IDS.has(indicatorId)) return Math.round(num * 100) / 100; if (indicatorId >= 1 && indicatorId <= 462) return Math.round(num / 1000 * 100) / 100; if (indicatorId === 623) return Math.round(num / 1000 * 100) / 100; return Math.round(num * 100) / 100; // fallback directo } ``` ### Reglas simplificadas | Tipo | IDs | Acción | Unidad | |---|---|---|---| | **DIRECTOS** | 1001, 600, 1293, 2038-2067, 2052, 10351, 10352, 10206, 10006, 10232, 2198, 2199, 1777-1780, 10358, 10359, 10355, 10356, 10207-10209 | Valor directo | MW o €/MWh o tCO₂ | | **PBF/programados** | 1-462 (PBF), 623 (hidráulico), 10035-10049 | ÷ 1000 | GWh/periodo (MW·h) | ### ⚠️ IDs CORRECTOS de previsión D+1 | Concepto | ID | Unidad | |---|---|---| | Demanda prevista | **2052** | MW | | Eólica prevista | **1777** | MW | | Solar prevista | **1779** | MW | | Renovable prevista | **10358** | MW | ### ⚠️ IDs CORRECTOS de interconexión | Concepto | ID | Unidad | |---|---|---| | Francia | **10207** | MW directo | | Portugal | **10208** | MW directo | | Marruecos | **10209** | MW directo | --- ## 3. Deploy en NaN.builders ### Estructura del deploy 1. **Push a GitHub** → NaN detecta y hace build con Kaniko 2. **Kaniko build** → construye la imagen Docker sin daemon 3. **Auto-deploy** → si el build funciona, se despliega automáticamente ### Patrón de archivos .env ``` proyecto/ ├── .env ← local, NO en Git (desarrollo) ├── .env.example ← SÍ en Git (documentación) ├── .dockerignore ← excluye .env, node_modules, .git └── .gitignore ← excluye .env ``` ### Dockerfile mínimo para NaN ```dockerfile FROM node:20-alpine AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --omit=dev FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production ENV PORT=4000 RUN addgroup -S appgroup && adduser -S appuser -G appgroup COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules COPY package.json ./ COPY server.js ./ COPY src/ ./src/ COPY public/ ./public/ COPY data/ ./data/ USER appuser EXPOSE 4000 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD wget -qO- http://localhost:4000/healthz || exit 1 CMD ["node", "server.js"] ``` ### Reglas críticas - **Puerto:** El Dockerfile EXPOSE debe coincidir con el puerto del espacio NaN - **Variables de entorno:** Se configuran en la web de NaN → pestaña **Env** - **Kaniko:** No soporta `--build-arg` para secrets → usar variables de entorno ### Health endpoints - `/healthz` — `{status: "ok"}` — verifica que el app está vivo - `/readyz` — verifica que los tokens están configurados ### Trigger redeploy ```bash git commit --allow-empty -m "chore: trigger redeploy" git push ``` --- ## 4. Dashboard Frontend Troubleshooting ### Problemas comunes #### 1. Dashboard se queda en "Cargando..." para siempre **Causa:** Error JS no capturado que no oculta el loading overlay. **Verificar:** - `showLoading` existe en `utils.js` - `utils.js` se carga ANTES que `data.js` en el HTML - `setupDateNavigation` y `updateDateControls` están DEFINIDAS en `data.js` #### 2. API responde 5.2s+ en NaN pero 0.5s local **Causa:** Disk cache se pierde entre reinicios en NaN. **Solución:** Memory cache en `server.js` + batching paralelo (5 por batch × 3 concurrentes) + timeout 15s + 2 reintentos con backoff. #### 3. CDN/NaN cachea versión vieja del HTML **Solución:** Meta tags `Cache-Control: no-cache` + `cache-bust.js` + deploy vacío. #### 4. NaN sirve versión antigua de archivos JS (página en blanco) **Solución:** `git commit --allow-empty` + `git push` → esperar 2-3 min → verificar hashes. #### 5. Frontend tarda 10s+ en mostrar datos **Solución:** Carga progresiva — mostrar summary primero, prediccion en segundo plano. ### Verificación rápida ```bash curl -s -o /dev/null -w "HTML: %{http_code} %{size_download}\n" URL curl -s -w "SUMMARY: %{http_code} %{time_total}s\n" URL/api/esios/summary?fecha=2026-05-30 curl -s URL/js/data.js | head -c 100 curl -s URL/js/cache-bust.js ``` --- ## 5. Informe Telegram ### Script `scripts/esios-telegram.js` — Node.js puro + canvas npm ### Envía 1. **Texto resumen** con análisis automático (precios, demanda, renovables, CO2, interconexiones) 2. **5 gráficos PNG** con Canvas: PVPC, Demanda, Solar vs Demanda, Interconexiones, CO2 ### Variables de entorno - `TELEGRAM_BOT_TOKEN` — token del bot - `TELEGRAM_CHAT_ID` — chat de destino - `ESIOS_API_TOKEN` — token ESIOS/REE ### Pitfalls - **NUNCA usar IDs 10035-10043** — devuelven null - **Interconexiones:** valores negativos = importación, mostrar línea de cero - **Unidades:** >= 1000 MW → GW, < 1000 MW → MW. NUNCA "k MW" - **Cron jobs no heredan variables** — el script lee de `/proc/1/environ` y `/hermes-home/.env` ### Gráficos Todos usan `drawLineChart()` con: - Fondo oscuro `#0f172a` - Colores: azul `#2563eb`, naranja `#f97316`, verde `#22c55e`, amarillo `#eab308` - Opciones: `stacked: false`, `showZero: true` --- ## 7. Sistema de Previsión de Precios (Forecast) **Archivo principal:** `src/domains/forecast/price-forecast.service.js` **Frontend:** `public/js/render-forecast.js` **Endpoint:** `GET /api/esios/forecast?days=90` (default 90, max 365, min 10 válidos) **Cache:** 6h en memoria (`server.js` cache object) ### Arquitectura 3 fuentes de datos → 14 features → correlación Pearson → regresión lineal → escenarios P10/P50/P90 **Fuentes:** - ESIOS/REE: 9 indicadores (IDs 1001, 1293, 1000, 2038-2044, 2067) - Open-Meteo Archive: 1 llamada por rango completo (NO 1/día) — Madrid 40.4165°N, -3.7026°W - Yahoo Finance TTF: 1 llamada reutilizada (NO 1/día) — ticker `TTF=F` **IDs CORRECTOS:** | ID | Concepto | Unidad | |---|---|---| | 1001 | PVPC | €/MWh | | 1293 | Demanda real | MW | | 1000 | Eólica | MW | | 2038 | Hidráulica | MW | | 2039 | Solar fotovoltaica | MW | | 2040 | Carbón | MW | | 2041 | Fuel + Gas | MW | | 2044 | Nuclear | MW | | 2067 | Ciclo combinado | MW | **⚠️ ID MAP CRÍTICO (errores anteriores):** - 2038 = Hidráulica (NO eólica) - 2039 = Solar FV (NO nuclear) - 2044 = Nuclear (NO solar) - 2067 = Ciclo combinado (NO hidráulica) - 1000 = Eólica **Optimización:** 1 llamada Open-Meteo por rango (archive-api.open-meteo.com) + 1 llamada TTF = ~4-5s para 90 días (antes timeout) **Algoritmo:** 1. `collectAllData(days, token)` — batches de 5 días ESIOS + 1 llamada clima + 1 llamada TTF 2. `buildDayFeatures()` — 14 features por día (precio, demanda, % tecnología, clima, TTF) 3. `calcularCorrelaciones()` — Pearson entre cada feature y precio (mínimo 5 puntos) 4. `analisisSensibilidad()` — regresión lineal simple (€/MWh por unidad de cambio) 5. `generarEscenarios()` — P10/P50/P90 con ajustes por renovables (-0.5€/MWh por %), TTF (+0.15€/MWh sobre 30), temperatura (+0.3€/MWh por °C sobre 20) **Frontend:** cada sección explica metodología, fuentes y fórmulas. No usar `buildSummary()` recursivamente (causa OOM en NaN). ### Pitfalls del forecast - **ID map erróneo:** El mapeo de IDs a variables era incorrecto (2038→eólica en vez de hidráulica). Usar siempre `INDICATORS` object en `price-forecast.service.js` como fuente de verdad. - **% por tecnología:** Se calcula como `media_diaria_tecnología / total_generacion_mw * 100`, NO suma bruta de valores. - **Mínimo 10 días válidos:** Si `validos.length < 10`, el endpoint devuelve error con explicación. - **NUNCA llamar `buildSummary()` desde render de tab** → causa OOM en NaN 1vCPU.
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub