|
| 1 | +# Helios |
| 2 | + |
| 3 | +<p align="center"> |
| 4 | + <a href="README.md">English</a> | |
| 5 | + <a href="README.es.md">Español</a> |
| 6 | +</p> |
| 7 | + |
| 8 | +<p align="center"> |
| 9 | + <picture> |
| 10 | + <source media="(prefers-color-scheme: dark)" srcset="assets/hero-es-dark.png"> |
| 11 | + <source media="(prefers-color-scheme: light)" srcset="assets/hero-es-light.png"> |
| 12 | + <img alt="Vista Hoy de Helios con curvas de producción y consumo en vivo, el diagrama de flujo de energía y los totales del día: producción, consumo, batería, autoconsumo y balance de red" src="assets/hero-es-light.png" width="800"> |
| 13 | + </picture> |
| 14 | +</p> |
| 15 | + |
| 16 | +> Repo **privado**. Este README no es para vender el proyecto: es para que el |
| 17 | +> Nacho del futuro entienda en cinco minutos **por qué existe esto, de dónde |
| 18 | +> salió y por qué está hecho como está hecho**, sin tener que re-leerse todo |
| 19 | +> el código. |
| 20 | +
|
| 21 | +Helios es el monitor solar de casa: dos inversores (Solis 4,4 kWp + Fox |
| 22 | +2,7 kWp), una batería de 5 kWh, más de 798 días de histórico, datos en |
| 23 | +vivo desde Home Assistant y el ahorro en euros calculado con nuestra |
| 24 | +tarifa real de Octopus. Un único servicio Node + SQLite corriendo en un |
| 25 | +LXC de casa. Sin nube. |
| 26 | + |
| 27 | +## ¿Por qué existe? |
| 28 | + |
| 29 | +Las apps de los fabricantes (Solis Cloud y similares): |
| 30 | + |
| 31 | +- Viven en la nube del fabricante: si cae su servicio o cambian la API, te |
| 32 | + quedas sin tus datos. Que encima son **tuyos**, y ni siquiera los puedes |
| 33 | + exportar bien. |
| 34 | +- Actualizan cada 5+ minutos y con retraso. Nada de "ahora mismo". |
| 35 | +- No mezclan ambos inversores ni cruzan la producción con el precio real |
| 36 | + de la luz para decirte cuánto **dinero** te estás ahorrando. |
| 37 | + |
| 38 | +Helios nace para tener **en casa, en local y para siempre** la telemetría |
| 39 | +de la instalación: qué produce cada inversor, qué consume la casa, cómo va |
| 40 | +la batería y cuánto vale en euros cada kWh autoconsumido. |
| 41 | + |
| 42 | +## Cómo ha crecido |
| 43 | + |
| 44 | +1. **Home Assistant (HAOS)** ya integraba los dos inversores, así que HAOS |
| 45 | + es la **fuente de verdad del dato en vivo** (sensores de potencia, |
| 46 | + batería, red). Helios no habla con los inversores: habla con HAOS. |
| 47 | +2. La primera versión fue un panel rápido de "producción vs consumo". |
| 48 | + Creció a multiusuario con roles, histórico, batería, precios y PWA. |
| 49 | +3. El histórico diario se importó desde HAOS y se sigue alimentando cada |
| 50 | + día: **798+ días** en una SQLite que es **intocable** (vive en |
| 51 | + `/opt/helios/data/helios.db` del CT 226; antes de cualquier migración, |
| 52 | + backup. Hay réplica Litestream con PITR al disco zfs_2tb de citadel-01). |
| 53 | +4. Un **scraper de Solis Cloud** (LXC 202 + add-on HAOS) complementa el |
| 54 | + dato cuando la integración local se queda corta. |
| 55 | + |
| 56 | +## Por qué este stack (y no otro) |
| 57 | + |
| 58 | +| Decisión | Motivo | |
| 59 | +|---|---| |
| 60 | +| **Node 22 + Hono** | Es una app de negocio/vista, no un colector 24/7: la lógica valiosa es la de agregados y saneado de datos, ya validada durante 798 días. Reescribirla en Go era riesgo puro sin ganancia (decisión cerrada 1-Ago-2026: Go = colectores/infra, Node = negocio). Hono porque es pequeño, rápido y sin magia. | |
| 61 | +| **better-sqlite3 (ESM plano)** | Una BD embebida transaccional es todo lo que necesita una app doméstica: cero servicios extra, backup trivial, y los 798 días caben en 90 MB. JS plano en vez de TS en el server: menos build, menos fricción; los contratos se garantizan con **schemas zod compartidos** (`shared/schemas.js`). | |
| 62 | +| **React 19 + Vite + Tailwind** | El mismo front de todas las apps de la casa (`webapp-shell` compartida): una sola forma de hacer shell, tema, ajustes y login. | |
| 63 | +| **HAOS como fuente del live** | HAOS ya mantiene las integraciones con Solis/Fox y sus reconexiones. Duplicar eso en Helios sería mantener dos drivers. Helios consume, no integra. | |
| 64 | +| **systemd + LXC, sin Docker** | Un binario de Node con `node_modules` y una unit hardenizada (`ProtectSystem`, `ReadWritePaths`) es más simple de razonar y de revertir que un contenedor, y la BD vive fuera del código en `/opt/helios/data`. | |
| 65 | +| **Litestream → SFTP** | Réplica continua de la SQLite con point-in-time-recovery: la BD es lo único insustituible del sistema. | |
| 66 | + |
| 67 | +## Qué cubre (requisitos de verdad) |
| 68 | + |
| 69 | +- **Multiusuario con roles** (admin/user), sesiones con cookie httpOnly, |
| 70 | + bcrypt, rate-limit de login, audit log y recovery de admin **solo desde |
| 71 | + localhost** (pensado para entrar por SSH al CT). |
| 72 | +- **i18n ES/EN/zh-CN** con idioma por usuario guardado en BD. |
| 73 | +- **Dato en vivo vía WebSocket a HAOS** (no REST lento): la vista Hoy y el |
| 74 | + flujo de energía se mueven en tiempo real. |
| 75 | +- **Histórico serio**: 798+ días con agregados diarios (producción, |
| 76 | + consumo, import/export de red, carga/descarga de batería, por inversor), |
| 77 | + autoconsumo, ahorro en € con precios Octopus y CO₂ evitado. |
| 78 | +- **PWA instalable**, tema claro/oscuro/auto (el auto va por hora solar, |
| 79 | + no por el sistema), densidad y shell común con el resto de apps de la |
| 80 | + casa. |
| 81 | +- **Sin Docker**: servicio systemd en un LXC de Proxmox, con la BD fuera |
| 82 | + del código para que las actualizaciones no la toquen. |
| 83 | + |
| 84 | +## Capturas (uso real, instalación en producción) |
| 85 | + |
| 86 | +**Histórico: agregados semanales, ahorro y CO₂** |
| 87 | + |
| 88 | +<picture> |
| 89 | + <source media="(prefers-color-scheme: dark)" srcset="assets/screenshot-history-es-dark.png"> |
| 90 | + <source media="(prefers-color-scheme: light)" srcset="assets/screenshot-history-es-light.png"> |
| 91 | + <img alt="Vista de histórico con barras de producción frente a consumo semanal, línea de autoconsumo, ahorro en euros y de dónde vino la energía" src="assets/screenshot-history-es-light.png" width="800"> |
| 92 | +</picture> |
| 93 | + |
| 94 | +**Batería: estado de carga y flujos** |
| 95 | + |
| 96 | +<picture> |
| 97 | + <source media="(prefers-color-scheme: dark)" srcset="assets/screenshot-battery-es-dark.png"> |
| 98 | + <source media="(prefers-color-scheme: light)" srcset="assets/screenshot-battery-es-light.png"> |
| 99 | + <img alt="Vista de batería con estado de carga, flujos de carga y descarga y uso diario de la batería" src="assets/screenshot-battery-es-light.png" width="800"> |
| 100 | +</picture> |
| 101 | + |
| 102 | +Las capturas son de la **instalación real** (server de desarrollo contra |
| 103 | +el HAOS local y una copia de la BD con 798 días). No hay dataset demo |
| 104 | +aparte: los datos de verdad cuentan mejor para qué sirve cada vista. |
| 105 | + |
| 106 | +## Arquitectura en 30 segundos |
| 107 | + |
| 108 | +``` |
| 109 | +Inversores (Solis/Fox) ──integraciones──▶ HAOS ──WebSocket──▶ Helios server (Hono) |
| 110 | + ▲ │ better-sqlite3 |
| 111 | + scraper Solis Cloud ▼ |
| 112 | + (LXC 202 + add-on) SQLite (798+ días) |
| 113 | + │ Litestream |
| 114 | + ▼ |
| 115 | + SFTP zfs_2tb (citadel-01) |
| 116 | +``` |
| 117 | + |
| 118 | +- `server/`: API Hono + auth multiusuario + agregados + saneado de datos. |
| 119 | +- `app/`: React 19 (vistas: Hoy, Inversores, Batería, Histórico, Ajustes). |
| 120 | +- `shared/schemas.js`: contrato zod server↔front. |
| 121 | +- Detalle completo en `ARCHITECTURE.md` y `STACK.md`. |
| 122 | + |
| 123 | +## Operación (lo justo para no romper nada) |
| 124 | + |
| 125 | +- Producción: **CT 226** (citadel-01), servicio `helios.service`, puerto |
| 126 | + 80 (solo LAN). La BD **no se toca** sin backup previo. |
| 127 | +- Desarrollo local: `PORT=8199 AUTH_PASS=… node server/src/index.js` |
| 128 | + desde `server/` (la BD de `server/data/` es una copia de desarrollo). |
| 129 | +- Si la contraseña de admin se pierde: `curl -X POST |
| 130 | + http://127.0.0.1:<puerto>/api/auth/recover` **desde el propio host** |
| 131 | + (SSH) devuelve una temporal. No funciona a través de proxy. |
| 132 | +- Actualizar = desplegar el build nuevo y reiniciar el servicio; la BD y |
| 133 | + el `.env` (`/opt/helios/`) sobreviven siempre. |
| 134 | + |
| 135 | +## Licencia |
| 136 | + |
| 137 | +Privada (repo sin publicar). Si algún día se publica, la casa usa |
| 138 | +AGPL-3.0, pero esa decisión se toma entonces, no ahora. |
0 commit comments