The Vault
iData · GreenPowerMonitor · archivo histórico PMGD

Bajamos todo el histórico de GPM
antes de que se nos corte el acceso.

El Vault es un coordinador que corre 24/7 y captura, día a día y planta por planta, cada canal que GreenPowerMonitor expone — strings, cajas, inversores, medidor y meteo — a un archivo permanente que controlamos nosotros. Lento, constante, a prueba de caídas.

Vivo ahora · último resultado capturado: CLL 2025-12-12 · 24,8 MB · 609 s
Días objetivo
13.296
COD→hoy · 16 plantas, 3 tenants
Capturados
2.440 18,3%
JSON permanente en disco
En cola
2.924
sembrados, esperando su turno
Huecos sin sembrar
7.932
aún sin entrar a la cola
01

Cómo funciona

Una sola regla de diseño: un plant-día por tick. En vez de un script gigante que baja todo de una y se cae a la mitad, una tabla en MySQL es la única fuente de verdad y cada tick de cron retoma exacto donde quedó el anterior.

1

Cron despierta cada 15 min trigger.php

Un cron llama por HTTPS a trigger.php?mode=vault-tick&key=…. El secreto se valida con hash_equals. (Se usa trigger por web porque el host a veces bloquea crontab directo.)

2

Elige el siguiente plant-día vault_queue

Recupera trabajos colgados (>30 min → pending), luego toma 1 fila: status IN (pending,backoff), next_attempt vencido, ORDER BY priority, pull_date → la historia más vieja primero.

3

Baja TODOS los canales del día kepler_raw_dump

Autentica (token cacheado 20 h), pide la lista de Element y Datasource, y recorre los ~4.500 datasources en lotes de 10 contra /api/DataList/v2 a 15 min, con 500 ms de pausa entre lotes. Si un lote falla, reintenta de a 3, luego de a 1, para aislar el ID malo.

4

Escribe un JSON permanente /dumps

Streaming a VER_2025-05-10.json con {meta, elements, datasources, values, stats}. Dump crudo: cada canal, sin filtrar — puerta de un solo sentido: un canal mal filtrado se pierde para siempre, el disco es trivial.

5

Juzga por el artefacto, no por el código de salida vault_state

Archivo >100 KB → done. 429/503/timeout → backoff (30 min × intentos). 401/403 → frena TODO 60 min (GPM pudo revocar acceso). 5 intentos → failed y sigue.

02

Dónde vive la data

Tres capas, una sola responsabilidad cada una: el dato crudo en disco, la coordinación en MySQL, y la vista para humanos en la web. Todo en el servidor cPanel home/ienergia; nada de esto pasa por GPM una segunda vez.

📦

El dato crudo

/public_html/idata.ienergia.cl/dumps/<PLANTA>_<FECHA>.json

Un archivo = un día completo de una planta entera, a 15 min. Accesible por URL. Los días viejos se comprimen a .gz.

  • meta + lista de elementos + datasources
  • valores de cada canal (~96 filas/día)
  • stats del pull (filas, fallidos, duración)
🗃️

La coordinación

MySQL · ienergia_idata

La memoria del Vault. Stateless entre corridas: reiniciar el server, matar el proceso o cerrar el browser no pierde nada.

  • vault_queue — la cola (única verdad)
  • vault_state — halt_until, last_tick, last_result
  • idata_plants — catálogo + mapping de IDs
📊

La vista

idata.ienergia.cl/vault_coverage.php

Dashboards de solo lectura, auto-refresco. Un calendario por planta desde el COD hasta hoy, celda a celda.

  • verde = capturado · ámbar = en cola
  • rojo = fallido · gris = hueco
  • latido: ¿el coordinador está vivo?
03

Cuánto hay y cuánto falta

Números en vivo del vault_coverage.php, leídos hoy. Hergo está casi completo; iEnergia tiene las plantas más antiguas (Calle Larga arranca en 2019, +2.600 días) y va parcial; Obton recién entra a la cola — solo Llancay está sembrado.

capturado en cola hueco (sin sembrar)
PlantaCODDíasCapturadoProgreso
04

Cómo se resuelve el mapping

GPM no es consistente: ni los nombres de planta ni los nombres de canal coinciden entre proyectos. El Vault resuelve esto en dos capas — y la jugada clave es no resolver la segunda capa al bajar.

Capa 1 · identidad de planta

Nombre GPM → código canónico

GPM llama a las plantas "CL - Aldebaran", "Hergo", "Hergo Los Eucaliptos"… El normalizador de discover.php quita acentos y el prefijo "CL - ", y empata por posición. El resultado se congela en idata_plants.source_plant_id.

"CL - Aldebaran" normalize() ALD · plantId 1571
Capa 2 · nomenclatura de canal

Se difiere, no se resuelve al bajar

Cada planta nombra distinto la caja, el string y la potencia. En vez de mapear al vuelo (y arriesgar perder un canal), el Vault baja todo crudo y guarda los nombres tal cual. El mapping de roles (string, CB, IMD, tracker) se resuelve después, offline, sobre el JSON ya seguro.

dump crudo elements+datasources role-map offline

El problema de la capa 2, concreto — cómo nombran la misma cosa (caja 4, string 8, potencia DC) cuatro plantas distintas:

PlantaCajaStringCanal de potencia DC del string
VeronaSCB 04String  05.01✓ DC POWER STRING 08
SalernoString Box 01.01String 10.05.04✓ DC POWER STRING 04
Calle LargaCB01CB01-S01S02~ Power (genérico)
San VicenteCB 01.01String 02.11.09✗ no existe (solo corriente)

Por eso la decisión de bajar crudo y completo no es pereza — es la única forma de que esa inconsistencia se pueda arreglar algún día sin haber tirado datos a la basura. El JSON guarda el árbol de elementos completo, así que el mapping de roles siempre se puede recomputar.

05

Por qué no se cae

El histórico es una carrera contra el reloj: GPM puede cortar el acceso en cualquier momento. El Vault está diseñado para sobrevivir todo lo que le pase al servidor.

🔁

Stateless entre corridas

La cola en MySQL es la única verdad. Reiniciar, matar el proceso o cortar la conexión → el siguiente tick sigue igual.

🧾

Juzga por el artefacto

No confía en el exit code: si el archivo quedó >100 KB es éxito; si "tuvo éxito" pero el archivo es chico, borra el parcial y reintenta.

Backoff exponencial

429/timeout → reintenta en 30 min × intentos. Respeta Retry-After. Cinco fallos → marca failed y sigue con otro día.

🛑

Freno de auth global

Un 401/403 detiene TODOS los ticks 60 min — GPM pudo revocar acceso; no insistir y quemar el rate limit.

🧩

Aísla IDs malos

Lotes de 10 → si fallan, de 3 → de 1. Un datasource corrupto no tumba el día entero.

🔌

Detach del cliente

ignore_user_abort + sin límite de tiempo: un tick dura ~9 min, pero si el curl del cron corta antes, el trabajo continúa.

El principio rector

“Lento, constante, sin parar.” Un plant-día cada 15 minutos no parece mucho, pero corre 24/7 sin supervisión y nunca pierde el lugar. Cada hueco gris que se vuelve verde es un día de generación que ya no depende de que GPM siga prestándonos sus servidores.

— mandato del 4-jun-2026 · programa actual: backfill priorizado por antigüedad