![]() |
| (Si quieres probar esta solución, al final dejo enlace de descarga del json NODE-RED) |
Cuando tu inversor «inteligente» en realidad no piensa
Si tienes placas y batería con Victron, seguro que conoces su modo "smart" ESS. Funciona, sí… pero su parte «inteligente» es limitada y a mí no me servía (no vendo a red). Yo quería decidir de verdad: cuándo merece la pena cargar de la red barata, cuándo tirar de batería y —sobre todo— cuánto hueco dejarle al sol para no desperdiciar ni un rayo. Y, ya puestos, sin maltratar las celdas.
Como el Smart ESS de Victron me daba poquísimo control sobre sus decisiones, me puse manos a la obra. Fui construyendo —con ayuda de la IA— mi propio gestor en Node-RED, y lo he ido ampliando hasta que por fin aprovecha la batería como yo quería. Te cuento cómo piensa.
Tres objetivos que tiran cada uno para su lado
Todo el sistema intenta equilibrar tres cosas que muchas veces se pelean entre ellas:
- Pagar poco: comprar energía en las horas baratas y esquivar las caras si la simulación de consumo así lo indica (en períodos largos de precio bajo, cargar de día para aprovechar energías renovables).
- Exprimir el sol: si el sol va a llenar la batería gratis, no llenarla antes con la red.
- Cuidar la batería: nada de descargas a fondo ni de tenerla siempre a tope.
Dos cerebros que no se pisan
La idea central es que hay dos cerebros trabajando a la vez, cada uno a su ritmo:
El Cerebro (cada media hora)
Es el estratega. Cada 30 minutos hace una especie de simulación de las próximas 48 horas: junta el precio de la luz, la previsión del sol y mi consumo, y con eso calcula cuánta batería conviene tener. Funciona como una hucha lista: la llena cuando es barato o va a sobrar sol, y la vacía cuando toca aprovecharla.
El Vigilante (cada pocos segundos)
Es el guardaespaldas. Mientras el Cerebro hace estrategia, el Vigilante mira la tensión real de las celdas casi en tiempo real. Si nota que están sufriendo, frena la descarga al instante —antes de que salte la protección de la batería— y además aprende: ajusta el suelo mínimo para que no vuelva a pasar. Utilizo dos baterías LifePo4 DIY de 16 celdas con BMS, con un smartshunt de Victron, por lo que esto es importante.
Los trucos que lo hacen «listo»
- Deja sitio al sol: si la previsión dice que va a sobrar generación, baja el objetivo para que quepa. Cuanto más me fío del sol, más hueco reserva (y eso lo ajusto con un mando de «agresividad»).
- Carga en el último momento: en las horas baratas no llena de golpe; espera por si el sol adelanta el trabajo. Así no compra de más.
- Aprende mi consumo: calcula la media de gasto de los últimos 7 días, así afina mucho mejor cuánta batería necesito de noche.
- Modo finde: los fines de semana y festivos —que con mi tarifa son baratos las 24 h— mantiene la batería en una banda sana del 30-80 % y prioriza cargar a mediodía aprovechando el sol, en vez de la red de madrugada.
- No se cree el sol a ciegas: si la previsión es de mala calidad, se fía menos de ella y va más sobre seguro.
A prueba de sustos
Un sistema que manda sobre una batería tiene que aguantar incluso cuando le fallan sus propios sensores. Si el medidor de batería deja de dar el porcentaje, el gestor lo deduce a partir de la tensión; y si todo falla, se pone en modo seguro y no hace tonterías. De hecho, hace poco una actualización me dejó sin el dato de batería… y el sistema siguió funcionando sin que me enterara.
¿Y merece la pena?
No te voy a vender que sea perfecto ni el óptimo teórico —eso no existe—. Pero toma buenas decisiones, una tras otra, razonando con los datos que tiene y protegiéndose de los que le faltan. Y lo más importante para mí: aprovecha la batería como yo quería y la trata con mimo, que es lo caro.
El ahorro se nota, y mucho.
Enlace de descarga del archivo NODE RED: FLOWS optimizado
Notas: Nuestro Multiplus trabaja en una fase L1, 230V; por un lado está conectado a la red en la entrada 1 y en LOut2 está conectada la casa y también los paneles solares (en caso de pérdida de la red general, los paneles siguen funcionando ya que funcionaría como un SAI mientras tenga batería). Esto es la evolución de lo que ya conté en «Automatizando el aprovechamiento solar con batería». Si te animas a montar algo parecido, ya sabes el lema: querer es poder… poder es crear.
___________________________________________________
Aquí los detalles para los más técnicos:
Documento de Diseño del Sistema (System Design Document) de la instalación fotovoltaica y de almacenamiento. Refleja el comportamiento REAL del código en Node-RED (sincronizado con flows_optimizado.json), no la intención teórica. Cualquier ingeniero podría reimplementar el sistema completo a partir de aquí.
Visión Global del Ecosistema
Gestor de Energía Híbrido (EMS) Bi-Capa. Dos cerebros asíncronos que se comunican por memoria compartida (variables globales):
1. Capa Macro (Cerebro Principal): estratega económico y meteorológico. Previsión a 48 h. Se ejecuta cada 30 min.
2. Capa Micro (Vigilante Inteligente): guardaespaldas químico. Protege las celdas frente a caídas de tensión. Se dispara con la corriente de batería del SmartShunt, limitado a 1 ejecución cada 5 s.
Módulo 1: Cerebro Principal (Oráculo Predictivo v60.7)
Frecuencia: cada 30 min (xx:00 y xx:30).
Objetivo: minimizar coste de importación de red, maximizar autoconsumo solar y cuidar la salud de la batería.
1.1. Ingesta de Datos y Clasificación
* Tarifa FIJA: el sistema opera sobre una matriz de precios fija de 24 h (`PRECIOS_FALLBACK`, un patrón tipo 2.0TD: valle 0,084 / llano 0,116 / punta 0,195 €/kWh), que se trata de forma cíclica para cubrir las 48 h. El código admite precios dinámicos vía `msg.energy_prices` / `msg.energy_prices_tomorrow`, pero actualmente no hay fuente dinámica conectada, por lo que siempre usa la tarifa fija.
*Agnosticismo de calendario: ignora el día de la semana; solo obedece a la matriz de precios.
* Clasificación de zonas (sobre los precios del día ordenados):
* P3 (Valle): 25% de horas más baratas.
* P1 (Punta): 25% de horas más caras.
* P2 (Llano): 50% intermedio.
1.2. Motor de Integración Continua (Simulación 48h)
Recorre las próximas 48 h calculando el **Balance Neto** horario (Solar previsto − Consumo previsto). Si falta el consumo de una hora diurna (8–22 h) asume 500 W. De la curva acumulada extrae:
* Techo Ecológico (`socMaxEcologico`): a partir del pico de excedente solar futuro, deja hueco para no verter a red.
* Pulmón Elástico (hueco dinámico): con `AGRESIVIDAD_RESERVA_SOLAR = 40`, el hueco reservado al sol es dinámico entre 0% y 30% (NO un 20% fijo). `TARGET_PICO_DIARIO = 100 − hueco`, por lo que el techo varía entre 70% y 93% (tope del 93%, protege la bateria LFP y evita verter sol). La calibración mensual sí puede llegar al 100% (lo necesita para sincronizar el BMS); en operación normal el techo se limita al 93%, por lo que aun sin previsión de sol el objetivo máximo es 93%, no 100%.
* Supervivencia a Corto Plazo (`socSupervivenciaP2`): batería necesaria para cruzar las horas caras actuales hasta el próximo P3.
* Oasis Global (`socOasisGlobal`): déficit máximo en 48 h (permite comprar hoy si mañana no hay sol ni P3 suficiente).
1.3. Árbol de Decisión ("La Hucha Inteligente")
* P1: vaciado activo. Objetivo = suelo mínimo de seguridad.
* P2: mantenimiento. Objetivo = `min(techo ecológico, supervivencia P2)`.
* P3 diurno (10:00–18:00): acelerador solar JIT. Si el tiempo hasta el ocaso/fin de P3 ≤ horas necesarias de carga (+0,5 h de margen), inyecta carga hasta el objetivo diario; si no, espera y permite que el SOC caiga hasta un colchón de salud (`min(35%, techo)`).
* P3 nocturno/madrugada: si el bloque P3 alcanza el amanecer, delega la carga al sol de mañana; si no, aplica *Just-In-Time* sobre la **potencia neta** (potencia inversor − consumo medio), arrancando solo si las horas baratas restantes ≤ horas necesarias (+1 h de margen).
Modo Valle Prolongado (findes y precio plano 24 h)
En 2.0TD los fines de semana y festivos nacionales son valle las 24 h. Una capa de calendario marca sábados, domingos y festivos nacionales como tarifa plana, y cuando el precio del día es plano (rango < 0,005 €) se activa el Modo Valle Prolongado, que solo afecta a esos días (entre semana todo sigue igual):
- Banda saludable 30-80% (en vez de 20-93%): sin presión económica, se cicla suave por salud de la batería.
- Carga diurna 12-17 h dejando hueco al sol: el objetivo de mediodía es `80% − excedente solar esperado`, de modo que la red complementa al sol sin robarle sitio.
- Sin carga nocturna, salvo que el precio vaya a subir en < 8 h (entonces carga preventiva).
> Mejoras generales (también entre semana): el "oasis" de pre-compra se acota al próximo valle con capacidad de recarga (≥ 4 h) para no sobre-comprar; y la previsión solar se pondera por confianza (fuente sintética → se asume menos sol y se carga algo más).
> Agnóstico a la tarifa: la matriz de precios de 24 h vive en un único nodo de configuración (`tarifa_horaria`). Al cambiar precios o tramos ahí, todo el sistema (clasificación P1/P2/P3 por percentiles, detección de valle, findes, JIT, supervivencia) se recalibra automáticamente — no hay que tocar la lógica. Lo único que sigue ligado a la hora es la ventana de luz solar (10-18 h), que depende del sol, no de la tarifa.
1.4. Cortafuegos y Latch
* Corte Táctico de Subida (Guillotina): si la hora siguiente es más cara y estamos en el minuto ≥ 20, fuerza el objetivo al mínimo para evitar solapes de latencia.
* Latch Guardián (corregido): el comando se envía al inversor solo si `socFinal` difiere del ÚLTIMO valor realmente enviado (`ultimoSocPayload`) y además se cumple alguna de: ha cambiado la hora, el salto es ≥ 5%, o es una emergencia (corte táctico o calibración). Persiste `ultimoSocPayload` y `ultimaHoraEnviada`. Esto garantiza que el límite del inversor refleje el objetivo y re-afirma el valor al menos una vez por hora, sin reescrituras innecesarias.
* Suelo absoluto = `soc_minimo_base_permanent` (def. 20) + offset de seguridad. **Techo** = `TARGET_PICO_DIARIO` (o 100% en calibración).
Módulo 2: Vigilante Inteligente (Arco Reflejo v2.12)
Disparo: corriente de batería del SmartShunt (`battery/274 /Dc/0/Current`), pasada por un nodo delay que la limita a 1 ejecución cada 5 s (con "drop"). Así, 3 "strikes" = 15 s reales.
**Objetivo:** proteger frente a caídas de tensión (LVD) y adaptar el suelo mínimo si la batería se degrada.
2.1. Telemetría y Filtro de Espejismos (Sag)
* Lee la **corriente** del SmartShunt (convención: negativo = descarga) y, de variables globales, el **voltaje** (`Volt_bateria`) y el **SOC** (`current_soc`).
* **Filtro de amperaje:** umbral de sufrimiento **−15 A** (≈ 700–800 W de extracción). Si la batería descarga a más de 15 A, una caída de tensión se considera "Espejismo por Carga" (*Voltage Sag*) y se perdona.
2.2. Detección de Fatiga y Arco Reflejo
* Si el voltaje cae por debajo de **`VOLTAJE_CRITICO` = 46 V** (siendo > 0), no es un sag y la batería está descargando (entre 0 y −15 A), se anota un *strike*. El reflejo solo evalúa si el SOC está en zona de peligro (≤ suelo + 20).
* Tras **3 strikes consecutivos (15 s)** dispara el **Arco Reflejo**, con dos acciones:
1. **Freno inmediato:** escribe en el inversor un `MinimumSocLimit = max(nuevo suelo, SOC actual + 5)`, forzando a **detener la descarga al instante** y tomar energía de la red (protege las celdas de un corte brusco del BMS).
2. **Aprendizaje:** sube el suelo permanente (`soc_minimo_base_permanent`) **+5 puntos**.
* **Reset no rencoroso:** si en cualquier momento el voltaje sube de 46 V, deja de ser sag, o cesa la descarga, el contador de strikes se borra a cero (tiempo continuo).
2.3. Evolución Estructural (Aprendizaje)
* El reflejo solo actúa una vez por descarga: un candado (`bloqueo_aprendizaje`) impide volver a subir el suelo durante el mismo ciclo de descarga.
* El candado se "libera" cuando el voltaje supera `VOLTAJE_LLENO` = 50 V (la batería se está cargando), permitiendo otro +5 en un ciclo futuro si sigue habiendo sufrimiento.
* El suelo subido es permanente y no baja solo; se restaura manualmente con el nodo "Borrado_variables" (vuelve `soc_minimo_base_permanent` a 20% y limpia el estado del Vigilante).
Módulo 3: Previsión Solar y Consumo
Objetivo: alimentar el Motor de Integración del Cerebro. Salida normalizada a pares `[timestamp_ms, Wh]`.
* Previsión Solar (jerarquía de fallback): Solcast API → caché de Solcast → previsión de Victron VRM → curva sintética matemática (campana senoidal con factor estacional). Se suaviza la curva horaria. El estado del nodo indica la fuente activa (verde/amarillo/rojo).
* Previsión de Consumo: previsión de Victron VRM (`vrm_consumption_fc`), normalizada y filtrada a futuro; si falta, genera un perfil sintético (~12 kWh/día con curva horaria). El Cerebro asume 500 W en horas diurnas sin dato.
Módulo 4: Sistema de Calibración (v1.3)
Objetivo: evitar el drift del BMS/SmartShunt, inherente a la química LFP (curva de descarga muy plana).
* Detección de batería llena, por dos vías:
* Software: SOC ≥ 99%.
* Física (corriente de cola): SOC ≥ 95% y voltaje ≥ `VOLTAJE_ABSORCION` (54,0 V) y corriente absoluta ≤ 3 A (la batería ya rechaza carga).
* Hacen falta 2 ciclos consecutivos para confirmar; entonces se resetea el contador de 25 días y se baja la bandera `CALIBRANDO_BATERIAS`.
* Forzado mensual: si pasan 25 días sin alcanzar el 100%, dentro de las 8 horas diurnas más baratas (09:00–19:00) activa `CALIBRANDO_BATERIAS = true`. El Cerebro lo detecta y, en modo de autoridad máxima, ignora techo ecológico/hueco/tarifa y fija `socObjetivo = 100%` hasta que se confirma la sincronización.
Módulo 5: Robustez y Aprendizaje
5.1. Failsafe de SOC/Tensión (banco 16S). El nodo "Failsafe SOC/Tensión" es la fuente ÚNICA de `current_soc` y `Volt_bateria` efectivos. En operación normal pasa los valores reales del SmartShunt; si éste deja de refrescar (> 30 s) deduce el SOC de la tensión con una tabla OCV de 16S, usando una tensión redundante del VE.Bus (`vebus/275 /Dc/0/Voltage`) para sobrevivir a un fallo del SmartShunt. La estimación se compensa por corriente (si está disponible) y se acota en la zona plana. Si no hay ni SOC ni tensión de ninguna fuente, el Cerebro entra en modo seguro (suelo prudente 50%, no opera). La protección por tensión del Vigilante sigue activa mientras exista cualquier fuente de tensión.
Además, un guardián de tensión ligero (cada 5 s, independiente de la corriente) vigila la tensión efectiva cuando la corriente del SmartShunt está obsoleta: si cae por debajo de 47 V durante 15 s, fuerza un suelo de emergencia del 50% para detener la descarga. Cubre el caso de muerte del SmartShunt, en el que el Vigilante principal no puede ejecutarse (no recibe corriente).
5.2. Aprendizaje de consumo. (a) Media diaria de 7 días: mide el consumo AC real de la casa (`com.victronenergy.system`), lo integra a total diario y mantiene la media móvil de los últimos 7 días (`consumo_diario_medio_kwh`), persistida en `/data/nodered_consumo7d.json` (sobrevive a reinicios y actualizaciones de firmware; se guarda 1 vez/hora). Es la cifra de consumo de referencia cuando no hay previsión real — mucho más fiable que los 12 kWh fijos para cargar de noche a ciegas. (b) EWMA de carga base (`consumo_base_w`): media exponencial de la descarga nocturna, como señal secundaria.
5.3. Suelo aprendido con histéresis. El Vigilante sube el suelo (`soc_minimo_base_permanent`) +5 ante sufrimiento. Tras una carga sana/sincronizada, el suelo se relaja −5 (nunca por debajo del nivel confirmado). Si tras relajar vuelve a sufrir a ese nivel en la siguiente descarga, ese nivel queda confirmado/bloqueado (`soc_floor_confirmado`); los topes superiores nuevos sí se re-evalúan en cargas posteriores. Maximiza la capacidad usable sin perder protección.
5.4. Previsión sintética calibrada para Llodio. La curva de último recurso (cuando fallan Solcast, caché y VRM) usa factores mensuales rebajados por la nubosidad cantábrica (día medio, no día despejado), para no quedarse corto de batería en invierno asumiendo un sol que no llega.
Anexo: Estimador de Capacidad (v6.0)
Nodo independiente que deduce la capacidad real (kWh) de la batería por triangulación inversa: `Capacidad_Ah = (Ah_consumidos × 100) / (% faltante)`, convertida a kWh con **48 V** (16S; nominal real ~51,2 V). Solo calcula en zona fiable (**SOC < 90%**); por encima congela el dato (la fracción faltante es tan pequeña que dispararía el error). Filtro de cordura 5–150 kWh. El resultado alimenta `capacidad_bateria_estimada_kwh`, usado por el Cerebro.
Ficha técnica: Victron MultiPlus II · SmartShunt 500A · GX con Venus OS · batería LFP 16S (~48 V / ~30 kWh) · tarifa 2.0TD · Node-RED · previsión solar con Solcast y la API de VRM. Desarrollado con ayuda de la IA.


No hay comentarios:
Publicar un comentario
Puede dejar su comentario, que tratará de ser moderado en los días siguientes. En caso de ser algo importante/urgente, por favor utilicen el formulario de arriba a la derecha para contactar.