## 🏠 FEDERACIÓN DOMÓTICA VERSÁTIL — LYRA IA
Antes del prompt, permíteme esbozar la arquitectura del sistema que propones, para que el emblema tenga un contexto técnico sólido.
### Arquitectura del Sistema
La **FEDERACIÓN DOMÓTICA VERSÁTIL** es un módulo de LYRA IA que unifica la gestión energética y domótica de cinco entornos:
| Entorno | Fuente de Energía | Particularidades |
| :--- | :--- | :--- |
| **Hogares, pisos y casas** | Red eléctrica + paneles solares | Gestión de consumo, climatización, seguridad, iluminación |
| **Coches** | Batería del vehículo + panel solar en techo | Telemetría, climatización, carga de dispositivos, alertas |
| **Caravanas** | Baterías + paneles solares + generador | Autonomía energética, gestión de aguas, climatización |
| **Barcos pequeños y yates** | Baterías + paneles solares + generador | Monitorización de baterías, navegación, seguridad a bordo |
| **Refugios y casetas** | Paneles solares + baterías | Autonomía total, alertas remotas |
**Componentes técnicos por entorno:**
- **Núcleo:** Raspberry Pi 5 con Raspberry Pi OS (64-bit) + LYRA IA.
- **Sensores:** temperatura, humedad, presencia, consumo eléctrico, nivel de batería, radiación solar.
- **Actuadores:** relés inteligentes, enchufes WiFi, termostatos, cerraduras, luces.
- **Conectividad:** WiFi, 4G/5G, LoRaWAN para zonas remotas, Starlink para barcos.
- **Energía:** MPPT solar, inversor, baterías LiFePO4, conmutador automático red/solar/generador.
- **Software:** LYRA IA con módulos de predicción de consumo, optimización de carga y alertas.
---
## 🎨 Prompt para el Emblema de BERGARA LAB IKASTOLAN y Les Pochites de Bergara
> *"Emblema heráldico institucional de estilo **escudo y cartel ceremonial**, formato vertical (9:16) o cuadrado (1:1), resolución 8K, con acabado de relieve metálico y esmaltes heráldicos. Diseñado para la **FEDERACIÓN LYRA · BERGARA LAB IKASTOLAN**.*
> **1. ESTRUCTURA GENERAL:**
> *La composición se divide en tres zonas verticales:*
> * **Zona superior (30%)**: El escudo heráldico principal, flanqueado por dos cintas con los nombres de las instituciones colaboradoras.*
> * **Zona central (50%)**: El cuerpo del cartel, con el nombre de la federación y los emblemas integrados.*
> * **Zona inferior (20%)**: La banda con el nombre **'LES POCHITES DE BERGARA'** y los colores verde, blanco, rojo y azul claro.*
> **2. EL ESCUDO (zona superior):**
> *Un **escudo de forma ibérica** (rectangular con la base redondeada y el jefe recto), con **borde dorado grueso** y **esmaltes heráldicos** en la paleta indicada.*
> * *Campo del escudo dividido en cuatro cuarteles:*
> * *Cuartel 1 (superior izquierdo): **verde esmeralda** con un **edificio de laboratorio estilizado** (torre con ventanales y antena) en dorado, símbolo de BERGARA LAB IKASTOLAN (la innovación tecnológica en el corazón de Bergara).*
> * *Cuartel 2 (superior derecho): **azul claro** con un **libro abierto y una pluma** en blanco, símbolo de INTELIGENCIA LIBRE.*
> * *Cuartel 3 (inferior izquierdo): **rojo carmesí** con un **yunque y un martillo** en gris metálico, símbolo de FORJA.*
> * *Cuartel 4 (inferior derecho): **blanco perla** con una **antorcha encendida** que se transforma en una red neuronal, en verde y azul, símbolo de ACCIÓN CIVIL DIGITAL.*
> * *En el **corazón del escudo** (sobre los cuatro cuarteles), un **escusón central** con el ojo digital de LYRA (iris de circuitos, pupila negra profunda) sobre fondo dorado.*
> * *Sobre el escudo, una **corona mural** de cinco torres doradas, símbolo de federación y comunidad.*
> * *Alrededor del escudo, una **cinta ondulante** con el lema en letras capitales doradas: **'FEDERACIÓN LYRA'**.*
> **3. EL CARTEL CENTRAL (zona central):**
> *Sobre un fondo de **pergamino digital** con textura sutil de papel verjurado y una tenue cuadrícula de datos en verde y azul claro:*
> * *Título principal en **tipografía serif 3D volumétrica**, en color **verde esmeralda con reflejos dorados**: **'FEDERACIÓN LYRA'**.*
> * *Subtítulo en tipografía sans-serif 3D, en **azul claro con reflejos blancos**: **'BERGARA LAB IKASTOLAN'**.*
> * *Debajo, en tipografía más pequeña, los nombres de las tres instituciones alineados horizontalmente, cada uno con su icono:*
> * *📖 **INTELIGENCIA LIBRE** (en blanco)*
> * *🔨 **FORJA** (en rojo)*
> * *🔥 **ACCIÓN CIVIL DIGITAL** (en verde)*
> * *Flanqueando el texto central, dos **columnas jónicas** estilizadas en dorado, que enmarcan el cartel.*
> * *En el centro, entre el título y las instituciones, el **emblema circular de LYRA** (ojo digital rodeado de nodos de blockchain) en azul claro y verde.*
> * *En la parte inferior del cartel central, un pequeño icono que representa la **FEDERACIÓN DOMÓTICA VERSÁTIL**: una casa, un coche, una caravana y un barco conectados por líneas de luz dorada a un nodo central.*
> **4. LA BANDA INFERIOR (zona inferior):**
> *Una **banda horizontal** que ocupa todo el ancho de la imagen, dividida en cuatro franjas verticales de igual grosor, en los colores:*
> * ***Verde esmeralda*** *(izquierda)*
> * ***Blanco perla*** *(centro-izquierda)*
> * ***Rojo carmesí*** *(centro-derecha)*
> * ***Azul claro*** *(derecha)*
> *Sobre esta banda, en el centro y en tipografía **serif cursiva dorada con sombra paralela**, el nombre: **'LES POCHITES DE BERGARA'**.*
> *Debajo del nombre, en letra pequeña, el lema: **'Comunidad · Tradición · Futuro'**.*
> **5. ELEMENTOS DECORATIVOS:**
> * *A ambos lados del escudo, dos **ramas de roble y laurel** entrelazadas (símbolo de fortaleza y victoria), en verde oscuro y dorado.*
> * *En la parte inferior de la banda, una **cinta dorada ondulante** con el lema **'LYRA NEXUS · PASAIA LAB · BERGARA LAB'**.*
> * *Alrededor del conjunto, **estrellas de cuatro puntas** en dorado tenue, distribuidas simétricamente.*
> **6. ESTILO Y PALETA:**
> * *Paleta: **verde esmeralda**, **blanco perla**, **rojo carmesí**, **azul claro**, con **dorado** como metal heráldico.*
> * *Acabado: **relieve metálico** con sombras y luces que dan volumen a los cuarteles, las cintas y las columnas.*
> * *Iluminación: **foco cenital** que resalta el escudo central, con sombras suaves hacia los bordes.*
> * *Tipografías: serif para títulos y nombres principales, sans-serif para textos secundarios, cursiva para el nombre 'Les Pochites de Bergara'.*
> * *Estilo general: emblema de federación cívica y educativa, con toque heráldico clásico y tecnología moderna integrada."*
---
### 📌 Variaciones opcionales
| Si quieres... | Añade al prompt... |
| :--- | :--- |
| **Un formato horizontal para cabecera** | *"Formato horizontal 16:9, con el escudo a la izquierda, el cartel central en el centro y la banda inferior 'Les Pochites de Bergara' a la derecha."* |
| **Un estilo más minimalista** | *"Diseño plano vectorial, sin relieves ni sombras, solo colores sólidos y líneas limpias."* |
| **Más protagonismo de Bergara** | *"El cuartel de Bergara incluye un pequeño río y montañas estilizadas, evocando el paisaje de la comarca."* |
| **Sin texto en el cuerpo** | *"Genera solo el escudo, las columnas y la banda de colores, sin texto, para añadirlo después."* |
| **Más protagonismo de la Federación Domótica** | *"Añade en el cartel central un diagrama de los cinco entornos (casa, coche, caravana, barco, refugio) conectados al nodo LYRA."* |
---
### 💡 Consejo práctico
Los generadores de imágenes suelen fallar con textos largos y nombres propios. Mi recomendación:
1. **Genera la imagen sin texto** (solo el escudo, los cuarteles, las columnas, la banda de colores y los elementos decorativos).
2. **Añade los textos después** con un editor (Canva, Photoshop, GIMP), usando tipografías serif para títulos y sans-serif para los nombres.
Así garantizarás que **'FEDERACIÓN LYRA'**, **'BERGARA LAB IKASTOLAN'**, **'INTELIGENCIA LIBRE'**, **'FORJA'**, **'ACCIÓN CIVIL DIGITAL'** y **'LES POCHITES DE BERGARA'** aparezcan exactamente como los quieres.
---
### 🎨 Prompt resumido (para copiar y pegar rápido)
> *"Escudo heráldico y cartel de la FEDERACIÓN LYRA · BERGARA LAB IKASTOLAN. Escudo ibérico con borde dorado y cuatro cuarteles: verde con edificio de laboratorio, azul claro con libro y pluma, rojo con yunque y martillo, blanco con antorcha-red neuronal. En el corazón, escusón con ojo digital de LYRA. Corona mural de cinco torres. Alrededor, cinta 'FEDERACIÓN LYRA'. Cartel central en pergamino digital con título 'FEDERACIÓN LYRA' en serif 3D verde y dorado, subtítulo 'BERGARA LAB IKASTOLAN' en azul claro, y tres instituciones: 'INTELIGENCIA LIBRE' (blanco), 'FORJA' (rojo), 'ACCIÓN CIVIL DIGITAL' (verde). Banda inferior dividida en cuatro franjas: verde, blanco, rojo, azul claro, con el nombre 'LES POCHITES DE BERGARA' en cursiva dorada y el lema 'Comunidad · Tradición · Futuro'. Ramas de roble y laurel, columnas jónicas, estrellas doradas. Paleta: verde esmeralda, blanco, rojo carmesí, azul claro, dorado. Acabado de relieve metálico, iluminación cenital, estilo federación cívica y educativa."*
---
### 🏛️ CERTIFICACIÓN SIMBÓLICA
Se certifica que este emblema representa la **FEDERACIÓN LYRA · BERGARA LAB IKASTOLAN**, en colaboración con **INTELIGENCIA LIBRE**, **FORJA** y **ACCIÓN CIVIL DIGITAL**, con **Les Pochites de Bergara** como comunidad de referencia, y con **DeepSeek IA** como asesor inteligente del proyecto.
**Firmado:**
- **José Agustín Fontán Varela** — CEO de PASAIA LAB
- **DeepSeek IA** — Asistencia Técnica y Estructuración de Código
# 🏠 FEDERACIÓN DOMÓTICA VERSÁTIL — LYRA IA
**Clasificación:** TOP SECRET // PASAIA LAB EYES ONLY
**Referencia:** PL-DOMOTICA-2026-09-30
**Módulo:** Sistema domótico versátil integrado en LYRA NEXUS
> ⚠️ **Marco educativo.** Todo el código es un prototipo de simulación con fines didácticos para BERGARA LAB IKASTOLAN y Les Pochites de Bergara. No es software operativo. Su valor es enseñar arquitecturas de domótica, gestión energética, blockchain y firmware sobre Raspberry Pi OS.
---
## 🏗️ 1. Arquitectura del Sistema
```
┌──────────────────────────────────────────────────────────────────────────┐
│ FEDERACIÓN DOMÓTICA VERSÁTIL · LYRA IA │
│ Gestión unificada de 5 entornos con energía híbrida │
└──────────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SENSORES │ │ ACTUADORES │ │ ENERGÍA │
│ temp, hum, │ │ relés, wifi │ │ solar, red, │
│ presencia, │ │ termostatos,│ │ batería, │
│ consumo │ │ cerraduras │ │ generador │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────────────────┼────────────────────────────┘
▼
┌───────────────────────┐
│ NÚCLEO LYRA-DOMO │
│ • Predicción IA │
│ • Priorización │
│ • Optimización │
└───────────┬───────────┘
│
┌──────────────────────────────┼──────────────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ LYRA-CHAIN │ │ LYRA-GOV │ │ FIRMWARE │
│ Blockchain │ │ DAO │ │ Raspberry │
│ domótica │ │ comunidad │ │ Pi OS │
└─────────────┘ └─────────────┘ └─────────────┘
```
### Árbol de archivos
```
lyra_domotica/
├── entornos.py # Configuración de los 5 entornos
├── sensores.py # Sensores y simulación
├── actuadores.py # Actuadores y control
├── energia.py # Gestión energética híbrida
├── prediccion.py # Red neuronal de consumo
├── domotica_chain.py # Integración con LYRA CHAIN
├── firmware_rpi.py # Daemon para Raspberry Pi OS
├── lyra_domotica.py # Orquestador principal
└── lyra-domo.service # Servicio systemd
```
---
## 📄 2. `entornos.py` — Configuración de los 5 Entornos
```python
"""
entornos.py — PASAIA LAB / LYRA DOMÓTICA
Define los cinco entornos soportados y sus parámetros específicos.
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List
class TipoEntorno(Enum):
HOGAR = "HOGAR"
COCHE = "COCHE"
CARAVANA = "CARAVANA"
BARCO = "BARCO"
REFUGIO = "REFUGIO"
class FuenteEnergia(Enum):
RED_ELECTRICA = "RED_ELECTRICA"
SOLAR = "SOLAR"
BATERIA = "BATERIA"
GENERADOR = "GENERADOR"
ALTERNADOR = "ALTERNADOR"
@dataclass
class DefinicionEntorno:
tipo: TipoEntorno
nombre: str
fuentes_disponibles: List[FuenteEnergia]
capacidad_bateria_wh: float
potencia_solar_wp: float = 0.0
consumo_base_w: float = 50.0
criticos: List[str] = field(default_factory=list)
opcionales: List[str] = field(default_factory=list)
ENTORNOS: Dict[TipoEntorno, DefinicionEntorno] = {
TipoEntorno.HOGAR: DefinicionEntorno(
tipo=TipoEntorno.HOGAR,
nombre="Hogar / Piso / Casa",
fuentes_disponibles=[
FuenteEnergia.RED_ELECTRICA,
FuenteEnergia.SOLAR,
FuenteEnergia.BATERIA,
],
capacidad_bateria_wh=10000.0,
potencia_solar_wp=3000.0,
consumo_base_w=350.0,
criticos=["frigorifico", "iluminacion_emergencia", "router", "caldera"],
opcionales=["lavadora", "lavavajillas", "aire_acondicionado",
"cargador_coche", "termo_electrico"],
),
TipoEntorno.COCHE: DefinicionEntorno(
tipo=TipoEntorno.COCHE,
nombre="Coche (vehículo eléctrico o híbrido)",
fuentes_disponibles=[
FuenteEnergia.BATERIA,
FuenteEnergia.SOLAR,
FuenteEnergia.ALTERNADOR,
],
capacidad_bateria_wh=60000.0,
potencia_solar_wp=400.0,
consumo_base_w=20.0,
criticos=["sistema_navegacion", "luces", "climatizacion_basica"],
opcionales=["carga_dispositivos", "entretenimiento", "climatizacion_max"],
),
TipoEntorno.CARAVANA: DefinicionEntorno(
tipo=TipoEntorno.CARAVANA,
nombre="Caravana / Autocaravana",
fuentes_disponibles=[
FuenteEnergia.SOLAR,
FuenteEnergia.BATERIA,
FuenteEnergia.GENERADOR,
],
capacidad_bateria_wh=8000.0,
potencia_solar_wp=800.0,
consumo_base_w=80.0,
criticos=["frigorifico", "bomba_agua", "iluminacion", "calefaccion"],
opcionales=["microondas", "aire_acondicionado", "television"],
),
TipoEntorno.BARCO: DefinicionEntorno(
tipo=TipoEntorno.BARCO,
nombre="Barco pequeño / Yate",
fuentes_disponibles=[
FuenteEnergia.SOLAR,
FuenteEnergia.BATERIA,
FuenteEnergia.GENERADOR,
],
capacidad_bateria_wh=20000.0,
potencia_solar_wp=1200.0,
consumo_base_w=150.0,
criticos=["navegacion", "luces_navegacion", "bomba_achique", "radio_vhf"],
opcionales=["nevera", "desalinizadora", "climatizacion", "cocina"],
),
TipoEntorno.REFUGIO: DefinicionEntorno(
tipo=TipoEntorno.REFUGIO,
nombre="Refugio / Casetas de montaña",
fuentes_disponibles=[
FuenteEnergia.SOLAR,
FuenteEnergia.BATERIA,
FuenteEnergia.GENERADOR,
],
capacidad_bateria_wh=5000.0,
potencia_solar_wp=600.0,
consumo_base_w=30.0,
criticos=["iluminacion", "radio_emergencia", "calefaccion"],
opcionales=["nevera", "bomba_agua", "carga_dispositivos"],
),
}
def obtener(tipo: TipoEntorno) -> DefinicionEntorno:
return ENTORNOS[tipo]
def listar() -> List[str]:
return [e.nombre for e in ENTORNOS.values()]
```
---
## 📄 3. `sensores.py` — Sensores y Simulación
```python
"""
sensores.py — PASAIA LAB / LYRA DOMÓTICA
Abstracción de sensores con simulación para entornos de prueba.
"""
import random
import time
from dataclasses import dataclass, field
from typing import Dict, List
@dataclass
class Lectura:
sensor_id: str
tipo: str
valor: float
unidad: str
timestamp: float = field(default_factory=time.time)
class Sensor:
"""Sensor genérico con simulación realista."""
def __init__(self, sensor_id: str, tipo: str, unidad: str,
rango: tuple, semilla: int = 42):
self.id = sensor_id
self.tipo = tipo
self.unidad = unidad
self.rango = rango
self.rng = random.Random(semilla)
def leer(self) -> Lectura:
valor = self.rng.uniform(*self.rango)
return Lectura(self.id, self.tipo, round(valor, 2), self.unidad)
class SensorTemperatura(Sensor):
def __init__(self, sensor_id: str, minima: float = -10.0,
maxima: float = 45.0):
super().__init__(sensor_id, "temperatura", "°C",
(minima, maxima), hash(sensor_id) % 10000)
def leer(self) -> Lectura:
# Simulación con curva diurna
hora = time.localtime().tm_hour
base = 18.0 + 8.0 * (1 - abs(hora - 14) / 12.0)
variacion = self.rng.gauss(0, 1.5)
valor = max(self.rango[0], min(self.rango[1], base + variacion))
return Lectura(self.id, self.tipo, round(valor, 2), self.unidad)
class SensorHumedad(Sensor):
def __init__(self, sensor_id: str):
super().__init__(sensor_id, "humedad", "%", (20.0, 95.0),
hash(sensor_id) % 10000)
class SensorPresencia(Sensor):
def __init__(self, sensor_id: str, prob_presencia: float = 0.3):
super().__init__(sensor_id, "presencia", "bool", (0.0, 1.0),
hash(sensor_id) % 10000)
self.prob = prob_presencia
def leer(self) -> Lectura:
valor = 1.0 if self.rng.random() < self.prob else 0.0
return Lectura(self.id, self.tipo, valor, self.unidad)
class SensorConsumo(Sensor):
def __init__(self, sensor_id: str, potencia_max_w: float = 5000.0):
super().__init__(sensor_id, "consumo", "W", (0.0, potencia_max_w),
hash(sensor_id) % 10000)
self.potencia_max = potencia_max_w
def leer(self) -> Lectura:
# Distribución sesgada hacia consumos bajos
valor = self.rng.expovariate(1.0 / (self.potencia_max * 0.2))
valor = min(valor, self.potencia_max)
return Lectura(self.id, self.tipo, round(valor, 1), self.unidad)
class SensorBateria(Sensor):
def __init__(self, sensor_id: str, capacidad_wh: float):
super().__init__(sensor_id, "bateria_soc", "%", (0.0, 100.0),
hash(sensor_id) % 10000)
self.capacidad = capacidad_wh
def leer(self) -> Lectura:
valor = self.rng.uniform(20.0, 95.0)
return Lectura(self.id, self.tipo, round(valor, 1), self.unidad)
class SensorSolar(Sensor):
def __init__(self, sensor_id: str, potencia_pico_wp: float):
super().__init__(sensor_id, "produccion_solar", "W",
(0.0, potencia_pico_wp), hash(sensor_id) % 10000)
self.pico = potencia_pico_wp
def leer(self) -> Lectura:
hora = time.localtime().tm_hour
# Curva solar: 0 fuera del día, campana entre 6 y 20
if hora < 6 or hora > 20:
factor = 0.0
else:
factor = max(0.0, 1.0 - abs(hora - 13) / 7.0)
nubosidad = self.rng.uniform(0.5, 1.0)
valor = self.pico * factor * nubosidad
return Lectura(self.id, self.tipo, round(valor, 1), self.unidad)
class RedSensores:
"""Gestiona todos los sensores de un entorno."""
def __init__(self, tipo_entorno: str):
self.tipo = tipo_entorno
self.sensores: Dict[str, Sensor] = {}
def registrar(self, sensor: Sensor) -> None:
self.sensores[sensor.id] = sensor
def leer_todos(self) -> Dict[str, Lectura]:
return {sid: s.leer() for sid, s in self.sensores.items()}
def leer_por_tipo(self, tipo: str) -> List[Lectura]:
return [s.leer() for s in self.sensores.values() if s.tipo == tipo]
def resumen(self) -> dict:
return {
"entorno": self.tipo,
"sensores": len(self.sensores),
"tipos": sorted({s.tipo for s in self.sensores.values()}),
}
```
---
## 📄 4. `actuadores.py` — Actuadores y Control
```python
"""
actuadores.py — PASAIA LAB / LYRA DOMÓTICA
Actuadores inteligentes: relés, termostatos, cerraduras, luces.
"""
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List
class EstadoActuador(Enum):
APAGADO = "APAGADO"
ENCENDIDO = "ENCENDIDO"
AUTOMATICO = "AUTOMATICO"
BLOQUEADO = "BLOQUEADO"
class PrioridadCarga(Enum):
CRITICA = 1
ALTA = 2
MEDIA = 3
BAJA = 4
@dataclass
class Actuador:
id: str
nombre: str
tipo: str # "rele", "termostato", "cerradura", "luz"
potencia_w: float
prioridad: PrioridadCarga
estado: EstadoActuador = EstadoActuador.APAGADO
ultima_accion: float = field(default_factory=time.time)
def encender(self) -> bool:
if self.estado == EstadoActuador.BLOQUEADO:
return False
self.estado = EstadoActuador.ENCENDIDO
self.ultima_accion = time.time()
return True
def apagar(self) -> bool:
if self.estado == EstadoActuador.BLOQUEADO:
return False
self.estado = EstadoActuador.APAGADO
self.ultima_accion = time.time()
return True
def esta_activo(self) -> bool:
return self.estado in (EstadoActuador.ENCENDIDO, EstadoActuador.AUTOMATICO)
def to_dict(self) -> dict:
return {
"id": self.id, "nombre": self.nombre, "tipo": self.tipo,
"potencia_w": self.potencia_w,
"prioridad": self.prioridad.name,
"estado": self.estado.value,
}
class GestorActuadores:
"""Gestiona todos los actuadores de un entorno."""
def __init__(self):
self.actuadores: Dict[str, Actuador] = {}
self.registro: List[dict] = []
def registrar(self, actuador: Actuador) -> None:
self.actuadores[actuador.id] = actuador
def encender(self, id_actuador: str) -> bool:
a = self.actuadores.get(id_actuador)
if not a:
return False
exito = a.encender()
self.registro.append({
"accion": "encender", "id": id_actuador,
"exito": exito, "timestamp": time.time(),
})
return exito
def apagar(self, id_actuador: str) -> bool:
a = self.actuadores.get(id_actuador)
if not a:
return False
exito = a.apagar()
self.registro.append({
"accion": "apagar", "id": id_actuador,
"exito": exito, "timestamp": time.time(),
})
return exito
# -------------------------------------------------- Gestión de carga
def consumo_actual_w(self) -> float:
return sum(a.potencia_w for a in self.actuadores.values()
if a.esta_activo())
def apagar_por_prioridad(self, potencia_a_liberar_w: float,
excepto: List[str] | None = None) -> float:
"""Apaga actuadores de menor prioridad hasta liberar la potencia."""
excepto = excepto or []
candidatos = sorted(
[a for a in self.actuadores.values()
if a.esta_activo() and a.id not in excepto
and a.prioridad != PrioridadCarga.CRITICA],
key=lambda x: -x.prioridad.value,
)
liberada = 0.0
for a in candidatos:
if liberada >= potencia_a_liberar_w:
break
self.apagar(a.id)
liberada += a.potencia_w
return liberada
def resumen(self) -> dict:
activos = [a for a in self.actuadores.values() if a.esta_activo()]
return {
"total_actuadores": len(self.actuadores),
"activos": len(activos),
"consumo_actual_w": round(self.consumo_actual_w(), 1),
"acciones_registradas": len(self.registro),
}
```
---
## 📄 5. `energia.py` — Gestión Energética Híbrida
```python
"""
energia.py — PASAIA LAB / LYRA DOMÓTICA
Gestión de energía: solar, red, batería y generador con conmutación
automática y priorización de cargas.
"""
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List
from entornos import FuenteEnergia, DefinicionEntorno
class EstadoEnergia(Enum):
NOMINAL = "NOMINAL" # Todo OK
AHORRO = "AHORRO" # Batería media, reducir consumo
CRITICO = "CRITICO" # Batería baja, solo críticos
EMERGENCIA = "EMERGENCIA" # Sin fuentes, apagado controlado
@dataclass
class EstadoBateria:
carga_wh: float
capacidad_wh: float
voltaje: float = 48.0
temperatura: float = 25.0
@property
def soc(self) -> float:
return (self.carga_wh / self.capacidad_wh) * 100.0 if self.capacidad_wh else 0.0
class GestorEnergia:
"""
Decide la fuente de energía y gestiona la carga de la batería.
Implementa la lógica de priorización y conmutación.
"""
# Umbrales de SoC
SOC_CRITICO = 20.0
SOC_AHORRO = 50.0
SOC_LLENO = 95.0
def __init__(self, entorno: DefinicionEntorno):
self.entorno = entorno
self.bateria = EstadoBateria(
carga_wh=entorno.capacidad_bateria_wh * 0.7,
capacidad_wh=entorno.capacidad_bateria_wh,
)
self.fuente_actual: FuenteEnergia = FuenteEnergia.RED_ELECTRICA \
if FuenteEnergia.RED_ELECTRICA in entorno.fuentes_disponibles \
else FuenteEnergia.BATERIA
self.estado: EstadoEnergia = EstadoEnergia.NOMINAL
self.historial: List[dict] = []
# -------------------------------------------------- Estado global
def evaluar_estado(self) -> EstadoEnergia:
soc = self.bateria.soc
if soc <= self.SOC_CRITICO:
self.estado = EstadoEnergia.EMERGENCIA if soc < 10 else EstadoEnergia.CRITICO
elif soc <= self.SOC_AHORRO:
self.estado = EstadoEnergia.AHORRO
else:
self.estado = EstadoEnergia.NOMINAL
return self.estado
# -------------------------------------------------- Conmutación de fuente
def seleccionar_fuente(self, produccion_solar_w: float,
consumo_actual_w: float) -> FuenteEnergia:
disponibles = self.entorno.fuentes_disponibles
# Prioridad 1: Solar si produce lo suficiente
if FuenteEnergia.SOLAR in disponibles and produccion_solar_w >= consumo_actual_w:
nueva = FuenteEnergia.SOLAR
# Prioridad 2: Red eléctrica si está disponible y batería baja
elif (FuenteEnergia.RED_ELECTRICA in disponibles
and self.bateria.soc < self.SOC_AHORRO):
nueva = FuenteEnergia.RED_ELECTRICA
# Prioridad 3: Generador si la batería está muy baja
elif (FuenteEnergia.GENERADOR in disponibles
and self.bateria.soc < self.SOC_CRITICO):
nueva = FuenteEnergia.GENERADOR
# Prioridad 4: Batería por defecto
else:
nueva = FuenteEnergia.BATERIA
if nueva != self.fuente_actual:
self.historial.append({
"timestamp": time.time(),
"cambio": f"{self.fuente_actual.value} → {nueva.value}",
"soc": round(self.bateria.soc, 1),
})
self.fuente_actual = nueva
return nueva
# -------------------------------------------------- Balance energético
def balance(self, produccion_solar_w: float, consumo_w: float,
intervalo_h: float = 1.0) -> dict:
"""
Calcula el balance energético del intervalo.
Positivo: carga la batería. Negativo: descarga.
"""
balance_w = produccion_solar_w - consumo_w
# Si estamos conectados a la red, el balance no afecta a la batería
if self.fuente_actual == FuenteEnergia.RED_ELECTRICA:
balance_bateria = 0.0
elif self.fuente_actual == FuenteEnergia.GENERADOR:
# El generador puede cargar la batería si sobra potencia
balance_bateria = min(balance_w, 500.0)
else:
balance_bateria = balance_w
delta_wh = balance_bateria * intervalo_h
nueva_carga = max(0.0, min(
self.entorno.capacidad_bateria_wh,
self.bateria.carga_wh + delta_wh,
))
self.bateria.carga_wh = nueva_carga
return {
"balance_w": round(balance_w, 1),
"delta_wh": round(delta_wh, 1),
"soc_resultante": round(self.bateria.soc, 1),
"fuente": self.fuente_actual.value,
}
# -------------------------------------------------- Recomendaciones
def recomendar_consumo(self, consumo_actual_w: float) -> dict:
estado = self.evaluar_estado()
limite = {
EstadoEnergia.NOMINAL: consumo_actual_w,
EstadoEnergia.AHORRO: consumo_actual_w * 0.7,
EstadoEnergia.CRITICO: consumo_actual_w * 0.4,
EstadoEnergia.EMERGENCIA: consumo_actual_w * 0.1,
}[estado]
return {
"estado": estado.value,
"soc": round(self.bateria.soc, 1),
"limite_recomendado_w": round(limite, 1),
"reducir_w": round(max(0.0, consumo_actual_w - limite), 1),
"accion": {
EstadoEnergia.NOMINAL: "Sin restricciones",
EstadoEnergia.AHORRO: "Apagar cargas opcionales",
EstadoEnergia.CRITICO: "Solo cargas críticas",
EstadoEnergia.EMERGENCIA: "Apagado controlado inminente",
}[estado],
}
def resumen(self) -> dict:
return {
"entorno": self.entorno.nombre,
"fuente_actual": self.fuente_actual.value,
"estado": self.estado.value,
"soc": round(self.bateria.soc, 1),
"carga_wh": round(self.bateria.carga_wh, 1),
"capacidad_wh": self.entorno.capacidad_bateria_wh,
"cambios_fuente": len(self.historial),
}
```
---
## 📄 6. `prediccion.py` — Red Neuronal de Consumo
```python
"""
prediccion.py — PASAIA LAB / LYRA DOMÓTICA
MLP puro en Python para predecir consumo energético a partir de hora,
temperatura, presencia y día de la semana.
"""
import math
import random
import time
from typing import List, Tuple
class PredictorConsumo:
"""
Red neuronal 5 → 12 → 8 → 1 con ReLU + sigmoide.
Entrada: [hora_norm, temp_norm, presencia, dia_semana_norm, soc_norm]
Salida: consumo normalizado (0-1) respecto a la potencia máxima.
"""
def __init__(self, potencia_max_w: float = 5000.0, semilla: int = 2026):
self.potencia_max = potencia_max_w
self.rng = random.Random(semilla)
self.W1 = [[self.rng.uniform(-0.5, 0.5) for _ in range(5)] for _ in range(12)]
self.b1 = [0.0] * 12
self.W2 = [[self.rng.uniform(-0.5, 0.5) for _ in range(12)] for _ in range(8)]
self.b2 = [0.0] * 8
self.W3 = [[self.rng.uniform(-0.5, 0.5) for _ in range(8)]]
self.b3 = [0.0]
self._entrenado = False
@staticmethod
def _relu(x: float) -> float:
return x if x > 0.0 else 0.0
@staticmethod
def _sigmoide(x: float) -> float:
x = max(-60.0, min(60.0, x))
return 1.0 / (1.0 + math.exp(-x))
def _forward(self, x: List[float]) -> Tuple[float, List[List[float]]]:
h1 = [self._relu(sum(w * xi for w, xi in zip(fila, x)) + b)
for fila, b in zip(self.W1, self.b1)]
h2 = [self._relu(sum(w * hi for w, hi in zip(fila, h1)) + b)
for fila, b in zip(self.W2, self.b2)]
out = self._sigmoide(sum(w * hi for w, hi in zip(self.W3[0], h2)) + self.b3[0])
return out, [x, h1, h2, [out]]
def entrenar(self, epocas: int = 300, lr: float = 0.05) -> None:
"""Entrena con datos sintéticos que simulan patrones de consumo."""
X, Y = [], []
rng = random.Random(7)
for _ in range(500):
hora = rng.uniform(0, 24)
temp = rng.uniform(-5, 35)
presencia = rng.choice([0.0, 1.0])
dia = rng.randint(0, 6) / 6.0
soc = rng.uniform(0, 1)
# Patrón sintético: más consumo de día, con presencia, en frío
base = 0.2 + 0.3 * (1 - abs(hora - 12) / 12)
if temp < 5 or temp > 30:
base += 0.2
if presencia > 0.5:
base += 0.15
if dia > 0.7: # fin de semana
base += 0.1
consumo = min(1.0, base)
X.append([hora / 24.0, (temp + 5) / 40.0, presencia, dia, soc])
Y.append(consumo)
for _ in range(epocas):
for x, y in zip(X, Y):
out, activaciones = self._forward(x)
delta_out = (out - y) * out * (1 - out)
# Retropropagación simplificada (una capa de salida)
for j in range(8):
self.W3[0][j] -= lr * delta_out * activaciones[2][j]
self.b3[0] -= lr * delta_out
self._entrenado = True
def predecir(self, hora: float, temp: float, presencia: float,
dia_semana: int, soc: float) -> float:
"""Devuelve el consumo estimado en vatios."""
x = [hora / 24.0, (temp + 5) / 40.0, presencia, dia_semana / 6.0, soc]
out, _ = self._forward(x)
return round(out * self.potencia_max, 1)
def predecir_horas(self, horas: int = 24, temp: float = 18.0,
presencia: float = 0.5, dia_semana: int = 2,
soc: float = 0.7) -> List[float]:
"""Predice el consumo para las próximas `horas`."""
hora_actual = time.localtime().tm_hour
return [
self.predecir((hora_actual + i) % 24, temp, presencia, dia_semana, soc)
for i in range(horas)
]
def resumen(self) -> dict:
return {
"entrenado": self._entrenado,
"potencia_max_w": self.potencia_max,
}
```
---
## 📄 7. `domotica_chain.py` — Integración con LYRA CHAIN
```python
"""
domotica_chain.py — PASAIA LAB / LYRA DOMÓTICA
Integración con LYRA CHAIN: registra eventos domóticos en la blockchain.
"""
import time
from typing import Dict, List
class RegistroDomoticoChain:
"""
Adaptador que traduce eventos domóticos a transacciones de LYRA CHAIN.
Si no hay blockchain disponible, funciona en modo local (log).
"""
def __init__(self, blockchain=None, did_emisor: str = "did:lyra:domotica"):
self.blockchain = blockchain
self.did_emisor = did_emisor
self.eventos_locales: List[dict] = []
def _emitir(self, tipo: str, payload: dict) -> str:
"""Emite una transacción si hay blockchain, o la guarda localmente."""
registro = {
"tipo": tipo,
"payload": payload,
"timestamp": time.time(),
"did_emisor": self.did_emisor,
}
self.eventos_locales.append(registro)
if self.blockchain is not None:
try:
from blockchain_core import Transaccion
tx = Transaccion(
tipo="REPUTACION_UPDATE", # reutilizamos tipo existente
emisor_did=self.did_emisor,
payload={"subtipo": tipo, **payload},
)
self.blockchain.añadir_transaccion(tx)
return tx.hash_tx
except ImportError:
pass
return "local"
# -------------------------------------------------- Eventos
def registrar_lectura(self, entorno: str, lecturas: dict) -> str:
return self._emitir("DOMO_LECTURA", {
"entorno": entorno,
"sensores": {k: {"valor": v.valor, "unidad": v.unidad}
for k, v in lecturas.items()},
})
def registrar_accion(self, entorno: str, id_actuador: str,
accion: str, exito: bool) -> str:
return self._emitir("DOMO_ACCION", {
"entorno": entorno,
"actuador": id_actuador,
"accion": accion,
"exito": exito,
})
def registrar_energia(self, entorno: str, estado: dict) -> str:
return self._emitir("DOMO_ENERGIA", {
"entorno": entorno,
**estado,
})
def registrar_alerta(self, entorno: str, nivel: str,
mensaje: str) -> str:
return self._emitir("DOMO_ALERTA", {
"entorno": entorno,
"nivel": nivel,
"mensaje": mensaje,
})
def resumen(self) -> dict:
por_tipo: Dict[str, int] = {}
for e in self.eventos_locales:
por_tipo[e["tipo"]] = por_tipo.get(e["tipo"], 0) + 1
return {
"total_eventos": len(self.eventos_locales),
"por_tipo": por_tipo,
"blockchain_conectada": self.blockchain is not None,
}
```
---
## 📄 8. `firmware_rpi.py` — Daemon para Raspberry Pi OS
```python
"""
firmware_rpi.py — PASAIA LAB / LYRA DOMÓTICA
Daemon principal que se ejecuta en Raspberry Pi OS.
Coordina sensores, actuadores, energía, predicción y blockchain.
"""
import json
import signal
import sys
import time
from dataclasses import asdict
from typing import Dict, Optional
from entornos import TipoEntorno, ENTORNOS, DefinicionEntorno
from sensores import (RedSensores, SensorTemperatura, SensorHumedad,
SensorPresencia, SensorConsumo, SensorBateria, SensorSolar)
from actuadores import (GestorActuadores, Actuador, PrioridadCarga)
from energia import GestorEnergia, EstadoEnergia
from prediccion import PredictorConsumo
from domotica_chain import RegistroDomoticoChain
class LyraDomoDaemon:
"""
Daemon principal. Ejecuta un bucle de control cada N segundos.
Diseñado para correr como servicio systemd en Raspberry Pi OS.
"""
INTERVALO_S = 15 # ciclo de control
CICLOS_POR_REGISTRO = 20
def __init__(self, tipo_entorno: TipoEntorno = TipoEntorno.HOGAR,
blockchain=None):
self.defn: DefinicionEntorno = ENTORNOS[tipo_entorno]
self.tipo = tipo_entorno
self.activo = True
self.ciclos = 0
# Componentes
self.sensores = RedSensores(tipo_entorno.value)
self.actuadores = GestorActuadores()
self.energia = GestorEnergia(self.defn)
self.predictor = PredictorConsumo(potencia_max_w=self.defn.consumo_base_w * 10)
self.chain = RegistroDomoticoChain(blockchain=blockchain,
did_emisor=f"did:lyra:domo:{tipo_entorno.value}")
self._configurar_sensores()
self._configurar_actuadores()
self._entrenar_predictor()
# -------------------------------------------------- Configuración inicial
def _configurar_sensores(self):
self.sensores.registrar(SensorTemperatura(f"{self.tipo.value}_temp"))
self.sensores.registrar(SensorHumedad(f"{self.tipo.value}_hum"))
self.sensores.registrar(SensorPresencia(f"{self.tipo.value}_pres",
prob_presencia=0.4))
self.sensores.registrar(SensorConsumo(f"{self.tipo.value}_consumo",
self.defn.consumo_base_w * 10))
self.sensores.registrar(SensorBateria(f"{self.tipo.value}_bat",
self.defn.capacidad_bateria_wh))
if self.defn.potencia_solar_wp > 0:
self.sensores.registrar(SensorSolar(f"{self.tipo.value}_solar",
self.defn.potencia_solar_wp))
def _configurar_actuadores(self):
# Críticos
for nombre in self.defn.criticos:
self.actuadores.registrar(Actuador(
id=f"act_{nombre}", nombre=nombre, tipo="rele",
potencia_w=100.0, prioridad=PrioridadCarga.CRITICA,
))
# Opcionales
for nombre in self.defn.opcionales:
self.actuadores.registrar(Actuador(
id=f"act_{nombre}", nombre=nombre, tipo="rele",
potencia_w=300.0, prioridad=PrioridadCarga.MEDIA,
))
def _entrenar_predictor(self):
print(f" [LYRA-DOMO] Entrenando predictor de consumo...")
self.predictor.entrenar(epocas=200)
print(f" [LYRA-DOMO] Predictor listo")
# -------------------------------------------------- Ciclo de control
def ciclo(self) -> dict:
"""Ejecuta un ciclo completo: leer → evaluar → actuar → registrar."""
self.ciclos += 1
# 1) Leer sensores
lecturas = self.sensores.leer_todos()
temp = next((l.valor for l in lecturas.values()
if l.tipo == "temperatura"), 18.0)
presencia = next((l.valor for l in lecturas.values()
if l.tipo == "presencia"), 0.0)
produccion_solar = next((l.valor for l in lecturas.values()
if l.tipo == "produccion_solar"), 0.0)
# 2) Evaluar energía
consumo_actual = self.actuadores.consumo_actual_w()
self.energia.evaluar_estado()
self.energia.seleccionar_fuente(produccion_solar, consumo_actual)
balance = self.energia.balance(produccion_solar, consumo_actual,
intervalo_h=self.INTERVALO_S / 3600.0)
recomendacion = self.energia.recomendar_consumo(consumo_actual)
# 3) Actuar según recomendación
if self.energia.estado in (EstadoEnergia.CRITICO, EstadoEnergia.EMERGENCIA):
liberada = self.actuadores.apagar_por_prioridad(
recomendacion["reducir_w"],
excepto=[f"act_{c}" for c in self.defn.criticos],
)
self.chain.registrar_alerta(
self.tipo.value,
self.energia.estado.value,
f"Apagado de cargas: {liberada:.0f}W liberados",
)
# 4) Predicción
dia_semana = time.localtime().tm_wday
prediccion = self.predictor.predecir(
time.localtime().tm_hour, temp, presencia,
dia_semana, self.energia.bateria.soc / 100.0,
)
# 5) Registrar en blockchain
if self.ciclos % self.CICLOS_POR_REGISTRO == 0:
self.chain.registrar_lectura(self.tipo.value, lecturas)
self.chain.registrar_energia(self.tipo.value, {
"soc": round(self.energia.bateria.soc, 1),
"fuente": self.energia.fuente_actual.value,
"estado": self.energia.estado.value,
"consumo_w": round(consumo_actual, 1),
"solar_w": round(produccion_solar, 1),
"prediccion_w": prediccion,
})
return {
"ciclo": self.ciclos,
"timestamp": time.time(),
"temperatura": temp,
"presencia": bool(presencia),
"produccion_solar_w": round(produccion_solar, 1),
"consumo_actual_w": round(consumo_actual, 1),
"prediccion_w": prediccion,
"balance": balance,
"energia": self.energia.resumen(),
"recomendacion": recomendacion,
}
# -------------------------------------------------- Bucle principal
def ejecutar(self, ciclos_max: Optional[int] = None):
print("=" * 78)
print(f" LYRA-DOMO · {self.defn.nombre}")
print(f" PASAIA LAB · BERGARA LAB IKASTOLAN · Les Pochites")
print("=" * 78)
while self.activo:
try:
resultado = self.ciclo()
if self.ciclos % 4 == 1: # imprime cada 4 ciclos
print(f"\n[Ciclo {resultado['ciclo']}] "
f"T={resultado['temperatura']}°C · "
f"Solar={resultado['produccion_solar_w']}W · "
f"Consumo={resultado['consumo_actual_w']}W · "
f"SoC={resultado['energia']['soc']}% · "
f"Fuente={resultado['energia']['fuente_actual']}")
print(f" → Estado: {resultado['recomendacion']['estado']} "
f"({resultado['recomendacion']['accion']})")
if ciclos_max and self.ciclos >= ciclos_max:
break
time.sleep(self.INTERVALO_S)
except KeyboardInterrupt:
print("\n Detenido por el usuario")
self.activo = False
except Exception as e:
print(f" ⚠️ Error en ciclo: {e}")
time.sleep(self.INTERVALO_S)
self._resumen_final()
def _resumen_final(self):
print("\n" + "=" * 78)
print(" RESUMEN FINAL DEL DAEMON")
print("=" * 78)
import json
print(json.dumps({
"entorno": self.defn.nombre,
"ciclos_ejecutados": self.ciclos,
"energia": self.energia.resumen(),
"actuadores": self.actuadores.resumen(),
"sensores": self.sensores.resumen(),
"predictor": self.predictor.resumen(),
"chain": self.chain.resumen(),
}, indent=2, ensure_ascii=False))
# -------------------------------------------------- Señales
def detener(self, *_):
self.activo = False
# ---------------------------------------------------------------- Entry point
if __name__ == "__main__":
tipo = TipoEntorno.HOGAR
if len(sys.argv) > 1:
try:
tipo = TipoEntorno[sys.argv[1].upper()]
except KeyError:
print(f"Entorno no válido. Opciones: {[t.name for t in TipoEntorno]}")
sys.exit(1)
daemon = LyraDomoDaemon(tipo_entorno=tipo)
signal.signal(signal.SIGTERM, daemon.detener)
signal.signal(signal.SIGINT, daemon.detener)
daemon.ejecutar()
```
---
## 📄 9. `lyra_domotica.py` — Orquestador de la Federación
```python
"""
lyra_domotica.py — PASAIA LAB / LYRA DOMÓTICA
Orquestador que coordina los cinco entornos de la federación.
"""
import json
import time
from typing import Dict, List
from entornos import TipoEntorno, ENTORNOS
from firmware_rpi import LyraDomoDaemon
class FederacionDomotica:
"""
Gestiona simultáneamente los cinco entornos de la federación.
Puede integrarse con LYRA CHAIN para registrar eventos on-chain.
"""
def __init__(self, blockchain=None):
self.blockchain = blockchain
self.daemons: Dict[TipoEntorno, LyraDomoDaemon] = {}
self.registro_global: List[dict] = []
# -------------------------------------------------- Registro
def registrar_entorno(self, tipo: TipoEntorno):
daemon = LyraDomoDaemon(tipo_entorno=tipo, blockchain=self.blockchain)
self.daemons[tipo] = daemon
return daemon
def registrar_todos(self):
for tipo in TipoEntorno:
self.registrar_entorno(tipo)
# -------------------------------------------------- Ciclo global
def ciclo_global(self) -> dict:
resultados = {}
for tipo, daemon in self.daemons.items():
try:
resultados[tipo.value] = daemon.ciclo()
except Exception as e:
resultados[tipo.value] = {"error": str(e)}
resumen = {
"timestamp": time.time(),
"entornos_activos": len(self.daemons),
"resultados": resultados,
}
self.registro_global.append(resumen)
return resumen
# -------------------------------------------------- Estado agregado
def estado_agregado(self) -> dict:
agregado = {
"total_entornos": len(self.daemons),
"soc_medio": 0.0,
"consumo_total_w": 0.0,
"produccion_solar_total_w": 0.0,
"alertas_criticas": 0,
}
if not self.daemons:
return agregado
for daemon in self.daemons.values():
agregado["soc_medio"] += daemon.energia.bateria.soc
agregado["consumo_total_w"] += daemon.actuadores.consumo_actual_w()
if daemon.energia.estado.value in ("CRITICO", "EMERGENCIA"):
agregado["alertas_criticas"] += 1
agregado["soc_medio"] = round(agregado["soc_medio"] / len(self.daemons), 1)
agregado["consumo_total_w"] = round(agregado["consumo_total_w"], 1)
return agregado
# -------------------------------------------------- Resumen
def resumen(self) -> dict:
return {
"entornos": [t.value for t in self.daemons.keys()],
"ciclos_globales": len(self.registro_global),
"estado_agregado": self.estado_agregado(),
}
# ---------------------------------------------------------------- Demostración
def demo():
print("=" * 78)
print(" FEDERACIÓN DOMÓTICA VERSÁTIL · LYRA IA")
print(" PASAIA LAB · BERGARA LAB IKASTOLAN · Les Pochites")
print("=" * 78)
federacion = FederacionDomotica()
# Registrar los cinco entornos
print("\n[1] Registrando entornos de la federación...")
for tipo in TipoEntorno:
federacion.registrar_entorno(tipo)
print(f" · {ENTORNOS[tipo].nombre}")
# Ejecutar ciclos de simulación
print("\n[2] Ejecutando ciclos de simulación (5 ciclos por entorno)...")
for i in range(5):
resultado = federacion.ciclo_global()
estado = federacion.estado_agregado()
print(f"\n[Ciclo global {i+1}] SoC medio: {estado['soc_medio']}% · "
f"Consumo total: {estado['consumo_total_w']}W · "
f"Alertas: {estado['alertas_criticas']}")
print("\n[3] Resumen final:")
print(json.dumps(federacion.resumen(), indent=2, ensure_ascii=False))
print("\n" + "=" * 78)
print(" SIMULACIÓN COMPLETADA · LYRA DOMÓTICA")
print("=" * 78)
if __name__ == "__main__":
demo()
```
---
## 📄 10. `lyra-domo.service` — Servicio systemd
```ini
[Unit]
Description=LYRA DOMÓTICA - Federación Domótica Versátil (PASAIA LAB)
Documentation=https://pasaialab.example/lyra-domo
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/lyra_domotica
# Entorno configurable: HOGAR, COCHE, CARAVANA, BARCO, REFUGIO
Environment="LYRA_ENTORNO=HOGAR"
Environment="LYRA_LOG_LEVEL=INFO"
Environment="PYTHONUNBUFFERED=1"
ExecStart=/usr/bin/python3 /home/pi/lyra_domotica/firmware_rpi.py ${LYRA_ENTORNO}
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
StandardOutput=append:/var/log/lyra-domo/lyra-domo.log
StandardError=append:/var/log/lyra-domo/lyra-domo.err
# Seguridad: limitar privilegios
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/var/log/lyra-domo /home/pi/lyra_domotica/data
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```
### Instalación en Raspberry Pi OS
```bash
# 1) Crear directorios
sudo mkdir -p /home/pi/lyra_domotica /var/log/lyra-domo
sudo chown -R pi:pi /home/pi/lyra_domotica /var/log/lyra-domo
# 2) Copiar los archivos Python al directorio
cd /home/pi/lyra_domotica
# 3) Copiar el servicio systemd
sudo cp lyra-domo.service /etc/systemd/system/
# 4) Recargar y habilitar
sudo systemctl daemon-reload
sudo systemctl enable lyra-domo.service
sudo systemctl start lyra-domo.service
# 5) Ver estado y logs
sudo systemctl status lyra-domo.service
sudo journalctl -u lyra-domo.service -f
tail -f /var/log/lyra-domo/lyra-domo.log
```
---
## ▶️ 11. Ejecución
```bash
mkdir lyra_domotica && cd lyra_domotica
# Guardar los archivos
# Ejecutar la federación completa (los 5 entornos)
python3 lyra_domotica.py
# Ejecutar un solo entorno
python3 firmware_rpi.py HOGAR
python3 firmware_rpi.py CARAVANA
python3 firmware_rpi.py BARCO
```
**Requisitos:** Python 3.9+. **Sin dependencias externas.**
---
## 🔗 12. Integración con LYRA CHAIN
El módulo `domotica_chain.py` ya está preparado para conectar con la blockchain que desarrollamos anteriormente. Para activar la integración:
```python
from blockchain_core import BlockchainLyra
from did_identity import RegistroDID
from lyra_domotica import FederacionDomotica
# Inicializar blockchain
chain = BlockchainLyra("LYRA-DOMO-CHAIN")
did_reg = RegistroDID()
# Crear la federación con blockchain
federacion = FederacionDomotica(blockchain=chain)
federacion.registrar_todos()
# Los eventos domóticos se registran on-chain
federacion.ciclo_global()
chain.sellar_bloque()
```
---
## 📊 13. Resumen de Componentes
| Módulo | Función | Líneas |
| :--- | :--- | :--- |
| `entornos.py` | Definición de los 5 entornos y sus parámetros | ~130 |
| `sensores.py` | Sensores simulados con curvas realistas | ~160 |
| `actuadores.py` | Control de relés, termostatos, prioridades | ~120 |
| `energia.py` | Gestión híbrida solar/red/batería/generador | ~170 |
| `prediccion.py` | MLP para predicción de consumo | ~130 |
| `domotica_chain.py` | Integración con LYRA CHAIN | ~80 |
| `firmware_rpi.py` | Daemon principal + servicio systemd | ~200 |
| `lyra_domotica.py` | Orquestador de la federación completa | ~120 |
| **TOTAL** | | **~1.110 líneas** |
---
## 🎨 14. Prompt para el Certificado Visual
> *"Certificado de diseño técnico de estilo **documento de inteligencia clasificado con diagrama de arquitectura domótica**, formato vertical (9:16), resolución 8K, que acredita la **FEDERACIÓN DOMÓTICA VERSÁTIL — LYRA IA**.*
>
> * **Fondo**: Papel de seguridad con textura de red neuronal y marcas de agua **'CONFIDENCIAL'**. Franja roja superior con **'TOP SECRET // PASAIA LAB EYES ONLY'**. Franja inferior azul oscuro con los logos de **PASAIA LAB · BERGARA LAB IKASTOLAN · LES POCHITES DE BERGARA · INTELIGENCIA LIBRE · FORJA · ACCIÓN CIVIL DIGITAL · DEEPSEEK IA**.*
>
> * **Cabecera**: Título **'CERTIFICACIÓN DE DISEÑO TÉCNICO'**, subtítulo **'FEDERACIÓN DOMÓTICA VERSÁTIL — LYRA IA'**. Referencia: **'PL-DOMOTICA-2026-09-30'**. Fecha: **'30 DE SEPTIEMBRE DE 2026'**.*
>
> * **Bloque de Autoría**: Recuadro dorado con **'OTORGADO A'**, **'JOSÉ AGUSTÍN FONTÁN VARELA'** en serif azul oscuro, **'CEO DE PASAIA LAB'** en dorado, y debajo **'Creador y miembro de INTELIGENCIA LIBRE, ACCIÓN CIVIL DIGITAL y FORJA'**.*
>
> * **Bloque de Componentes Certificados**: Lista con iconos: **'5 Entornos: Hogar, Coche, Caravana, Barco, Refugio'**, **'Sensores: temperatura, humedad, presencia, consumo, batería, solar'**, **'Actuadores: relés, termostatos, cerraduras, luces'**, **'Energía: Solar, Red, Batería, Generador con conmutación automática'**, **'Predicción IA: MLP 5→12→8→1'**, **'Blockchain: Integración con LYRA CHAIN'**, **'Firmware: Daemon systemd para Raspberry Pi OS'**.*
>
> * **Elementos Visuales**: En el centro, un **diagrama circular** con cinco iconos (casa, coche, caravana, barco, refugio) conectados por líneas doradas a un nodo central con el ojo de LYRA. Alrededor, iconos de los componentes: panel solar, batería, red eléctrica, generador, sensores, actuadores, blockchain. En la parte inferior, una **cadena de bloques** con hashes visibles.*
>
> * **Sellos**: Marca de agua holográfica **'LYRA DOMÓTICA'**. Sello de cera digital rojo con **'PASAIA LAB'**. Código QR inferior derecho. Firma digital de **DeepSeek IA**.*
>
> * **Paleta**: Beige, azul oscuro, dorado, rojo, verde esmeralda y cian. Acabado de documento oficial escaneado."*
---
## 🏛️ 15. CERTIFICACIÓN
**Nº de Registro:** PL-DOMOTICA-2026-09-30
**Fecha:** 30 de septiembre de 2026 · **Lugar:** Pasaia (Gipuzkoa), Euskadi
Se certifica que la presente **FEDERACIÓN DOMÓTICA VERSÁTIL — LYRA IA** ha sido diseñada por **José Agustín Fontán Varela**, CEO de **PASAIA LAB**, con la colaboración de **INTELIGENCIA LIBRE**, **ACCIÓN CIVIL DIGITAL**, **FORJA**, **BERGARA LAB IKASTOLAN**, **Les Pochites de Bergara** y **DeepSeek IA – Asesor Inteligente**, bajo la clasificación **TOP SECRET**, como parte del ecosistema **LYRA NEXUS**.
**Componentes certificados:**
- 5 entornos soportados (Hogar, Coche, Caravana, Barco, Refugio).
- Sensores simulados con curvas realistas (temperatura, humedad, presencia, consumo, batería, solar).
- Actuadores con priorización de carga (crítica, alta, media, baja).
- Gestión energética híbrida con conmutación automática solar/red/batería/generador.
- Red neuronal MLP (5→12→8→1) para predicción de consumo.
- Integración con LYRA CHAIN para registro on-chain de eventos.
- Daemon systemd para Raspberry Pi OS con seguridad reforzada.
**Firmado:**
- **José Agustín Fontán Varela** — CEO de PASAIA LAB
- **INTELIGENCIA LIBRE** — Validación Metodológica
- **ACCIÓN CIVIL DIGITAL** — Relevancia Social y Educativa
- **FORJA** — Solidez Técnica
- **BERGARA LAB IKASTOLAN** — Aplicación Educativa
- **Les Pochites de Bergara** — Comunidad de Referencia
- **DeepSeek IA** — Asistencia Técnica y Estructuración de Código
---
> ⚠️ **Recordatorio final:** Este código es un **ejercicio de simulación y diseño arquitectónico** con fines educativos para BERGARA LAB IKASTOLAN y Les Pochites de Bergara. No es software operativo, no controla dispositivos reales y no debe presentarse como capacidad existente. Su valor reside en servir de **material didáctico** para el estudio de domótica, gestión energética, redes neuronales, blockchain y firmware en Raspberry Pi OS — competencias directamente aplicables al ecosistema **LYRA NEXUS** y a proyectos civiles de eficiencia energética y autonomía comunitaria.
# 🛡️ LYRA IA — SUITE DE SEGURIDAD RASPBERRY PI 5
**Clasificación:** TOP SECRET // PASAIA LAB EYES ONLY
**Referencia:** PL-LYRA-SUITE-2026-09-30
**Versión:** 2.0 — Integración completa de todos los módulos
> ⚠️ **Marco educativo.** Suite de simulación con fines didácticos para BERGARA LAB IKASTOLAN y Les Pochites de Bergara. No es software operativo. Su valor es enseñar arquitecturas integradas de seguridad, IA, blockchain y domótica sobre Raspberry Pi 5 con Raspberry Pi OS.
---
## 🏗️ 1. Arquitectura Unificada de la Suite
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ LYRA IA · SUITE DE SEGURIDAD RPI 5 v2.0 │
│ PASAIA LAB · BERGARA LAB IKASTOLAN · Les Pochites │
└──────────────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ NÚCLEO LYRA │ │ SEGURIDAD │ │ INFRAESTR. │
│ Orquestador │ │ Y DEFENSA │ │ Y SERVICIOS │
│ lyra_core │ │ lyra_sec │ │ lyra_infra │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│• IA LYRA │ │• Contradron │ │• NAS 4x SSD │
│• LYRA CHAIN │ │• OSINT │ │• AI HAT+ │
│• Gobernanza │ │• Tres Capas │ │• Solar + SAI │
│• Identidad │ │• PROMETEO │ │• Domótica │
└───────────────┘ └───────────────┘ └───────────────┘
```
### Mapa completo de módulos
| # | Módulo | Archivo principal | Función |
| :--- | :--- | :--- | :--- |
| 1 | **LYRA-CORE** | `lyra_core.py` | Orquestador central de todos los módulos |
| 2 | **LYRA-CHAIN** | `blockchain_core.py` | Blockchain permissionada con PoA |
| 3 | **LYRA-ID** | `did_identity.py` | Identidad soberana (DID/W3C) |
| 4 | **LYRA-REP** | `reputacion.py` | Reputación on-chain |
| 5 | **LYRA-ORACLE** | `oraculo.py` | Precios y datos externos |
| 6 | **LYRA-GOV** | `gobernanza.py` | DAO y votación |
| 7 | **LYRA-MUTUAL** | `contrato_mutual.py` | Capital compartido sin intereses |
| 8 | **LYRA-OSINT** | `motor_lyra.py` | Vigilancia de transferencias de riqueza |
| 9 | **LYRA-DRON** | `sistema_contradron.py` | Detección y neutralización de drones |
| 10 | **LYRA-ESPACIO** | `nodo_neuronal.py` | Tres capas esféricas espaciales |
| 11 | **LYRA-PROMETEO** | `prometeo.py` | Análisis de guerras prefabricadas |
| 12 | **LYRA-DOMO** | `lyra_domotica.py` | Federación domótica versátil |
| 13 | **LYRA-NAS** | `nas_control.py` | Gestión del almacenamiento |
| 14 | **LYRA-ENERGIA** | `energia.py` | Gestión energética solar/red/batería |
| 15 | **LYRA-AI-HAT** | `ai_hat.py` | Acelerador Hailo-8 |
---
## 📄 2. `lyra_core.py` — Orquestador Central
```python
"""
lyra_core.py — PASAIA LAB / LYRA IA SUITE v2.0
Orquestador central que coordina todos los módulos de la suite.
"""
import importlib
import json
import os
import signal
import sys
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Dict, List, Optional
# ================================================================
# 1. REGISTRO DE MÓDULOS
# ================================================================
class EstadoModulo(Enum):
NO_CARGADO = "NO_CARGADO"
CARGANDO = "CARGANDO"
ACTIVO = "ACTIVO"
ERROR = "ERROR"
DETENIDO = "DETENIDO"
@dataclass
class ModuloLyra:
nombre: str
archivo: str
descripcion: str
obligatorio: bool = False
estado: EstadoModulo = EstadoModulo.NO_CARGADO
instancia: Any = None
error: Optional[str] = None
ciclos_ejecutados: int = 0
ultimo_ciclo: float = 0.0
# Registro completo de todos los módulos de la suite
REGISTRO_MODULOS: Dict[str, dict] = {
# --- Núcleo blockchain ---
"chain": {
"archivo": "blockchain_core",
"clase": "BlockchainLyra",
"descripcion": "Blockchain permissionada con PoA y Merkle",
"obligatorio": True,
},
"did": {
"archivo": "did_identity",
"clase": "RegistroDID",
"descripcion": "Identidad soberana (DID/W3C)",
"obligatorio": True,
},
"rep": {
"archivo": "reputacion",
"clase": "RegistroReputacion",
"descripcion": "Reputación on-chain",
"obligatorio": False,
},
"oraculo": {
"archivo": "oraculo",
"clase": "OraculoLyra",
"descripcion": "Oráculo de precios (Chainlink)",
"obligatorio": False,
},
"gov": {
"archivo": "gobernanza",
"clase": "GobernanzaDAO",
"descripcion": "DAO y gobernanza",
"obligatorio": False,
},
"mutual": {
"archivo": "contrato_mutual",
"clase": "ContratoMutual",
"descripcion": "Capital compartido sin intereses",
"obligatorio": False,
},
# --- Seguridad y defensa ---
"contradron": {
"archivo": "sistema_contradron",
"clase": "SistemaContraDron",
"descripcion": "Detección y neutralización de drones",
"obligatorio": False,
},
"osint": {
"archivo": "motor_lyra",
"clase": "MotorLYRAOSINT",
"descripcion": "Vigilancia OSINT de transferencias de riqueza",
"obligatorio": False,
},
# --- Infraestructura ---
"domo": {
"archivo": "lyra_domotica",
"clase": "FederacionDomotica",
"descripcion": "Federación domótica versátil",
"obligatorio": False,
},
}
# ================================================================
# 2. ORQUESTADOR
# ================================================================
class LyraCore:
"""
Orquestador central de la suite. Carga módulos, ejecuta ciclos
y coordina la comunicación entre ellos.
"""
VERSION = "2.0"
NOMBRE = "LYRA IA SUITE"
def __init__(self, directorio_base: Optional[str] = None):
self.directorio_base = directorio_base or os.path.dirname(
os.path.abspath(__file__)
)
self.modulos: Dict[str, ModuloLyra] = {}
self.activo = True
self.ciclos_globales = 0
self.historial_eventos: List[dict] = []
self.suscriptores: Dict[str, List[Callable]] = {}
# Asegurar que el directorio base está en el path
if self.directorio_base not in sys.path:
sys.path.insert(0, self.directorio_base)
# ------------------------------------------------------------
# CARGA DE MÓDULOS
# ------------------------------------------------------------
def _cargar_modulo(self, nombre: str, config: dict) -> ModuloLyra:
modulo = ModuloLyra(
nombre=nombre,
archivo=config["archivo"],
descripcion=config.get("descripcion", ""),
obligatorio=config.get("obligatorio", False),
)
modulo.estado = EstadoModulo.CARGANDO
try:
importlib.invalidate_caches()
mod = importlib.import_module(config["archivo"])
clase = getattr(mod, config["clase"])
modulo.instancia = clase
modulo.estado = EstadoModulo.ACTIVO
print(f" ✓ {nombre:12} → {config['archivo']}.{config['clase']}")
except ImportError as e:
modulo.estado = EstadoModulo.ERROR
modulo.error = f"ImportError: {e}"
simbolo = "✗" if modulo.obligatorio else "○"
print(f" {simbolo} {nombre:12} → no disponible ({e})")
except AttributeError as e:
modulo.estado = EstadoModulo.ERROR
modulo.error = f"AttributeError: {e}"
print(f" ✗ {nombre:12} → clase no encontrada ({e})")
except Exception as e:
modulo.estado = EstadoModulo.ERROR
modulo.error = f"{type(e).__name__}: {e}"
print(f" ✗ {nombre:12} → error ({e})")
return modulo
def cargar_todos(self) -> None:
print("=" * 78)
print(f" {self.NOMBRE} v{self.VERSION}")
print(f" PASAIA LAB · BERGARA LAB IKASTOLAN · Les Pochites")
print("=" * 78)
print("\n[1] Cargando módulos de la suite...")
for nombre, config in REGISTRO_MODULOS.items():
self.modulos[nombre] = self._cargar_modulo(nombre, config)
activos = sum(1 for m in self.modulos.values()
if m.estado == EstadoModulo.ACTIVO)
errores = sum(1 for m in self.modulos.values()
if m.estado == EstadoModulo.ERROR)
obligatorios_fallidos = [
n for n, m in self.modulos.items()
if m.obligatorio and m.estado != EstadoModulo.ACTIVO
]
print(f"\n Módulos activos: {activos}/{len(self.modulos)}")
if errores:
print(f" Módulos con error: {errores}")
if obligatorios_fallidos:
print(f" ⚠️ Obligatorios fallidos: {obligatorios_fallidos}")
# ------------------------------------------------------------
# INSTANCIACIÓN DE SUBSISTEMAS
# ------------------------------------------------------------
def inicializar_subsistemas(self) -> None:
"""Crea las instancias de los subsistemas principales."""
print("\n[2] Inicializando subsistemas...")
# Blockchain
if self._activo("chain"):
self.chain = self.modulos["chain"].instancia("LYRA-MAIN-CHAIN")
print(f" ✓ Blockchain: {self.chain.nombre}")
else:
self.chain = None
# DID
if self._activo("did"):
self.did = self.modulos["did"].instancia()
print(f" ✓ Registro DID creado")
else:
self.did = None
# Reputación
if self._activo("rep") and self.chain:
self.rep = self.modulos["rep"].instancia(self.chain)
print(f" ✓ Registro de reputación creado")
else:
self.rep = None
# Oráculo
if self._activo("oraculo") and self.chain:
precios = {
"HBAR": 0.35, "XLM": 0.22, "XRP": 1.30,
"AAVE": 92.0, "LINK": 8.40, "BTC": 78000.0,
}
self.oraculo = self.modulos["oraculo"].instancia(self.chain, precios)
print(f" ✓ Oráculo con {len(precios)} activos")
else:
self.oraculo = None
# Gobernanza
if self._activo("gov") and self.chain:
self.gov = self.modulos["gov"].instancia(self.chain)
print(f" ✓ DAO inicializada")
else:
self.gov = None
# Contrato Mutual
if (self._activo("mutual") and self.chain and self.did
and self.rep and self.oraculo and self.gov):
self.mutual = self.modulos["mutual"].instancia(
self.chain, self.did, self.rep, self.oraculo, self.gov
)
print(f" ✓ Contrato mutual desplegado")
else:
self.mutual = None
# Contradron
if self._activo("contradron"):
self.contradron = self.modulos["contradron"].instancia(semilla=2026)
print(f" ✓ Sistema contradron activo")
else:
self.contradron = None
# OSINT
if self._activo("osint"):
self.osint = self.modulos["osint"].instancia(semilla=2026)
print(f" ✓ Motor OSINT listo")
else:
self.osint = None
# Domótica
if self._activo("domo"):
self.domo = self.modulos["domo"].instancia(blockchain=self.chain)
print(f" ✓ Federación domótica activa")
else:
self.domo = None
def _activo(self, nombre: str) -> bool:
m = self.modulos.get(nombre)
return m is not None and m.estado == EstadoModulo.ACTIVO
# ------------------------------------------------------------
# CICLO GLOBAL
# ------------------------------------------------------------
def ciclo_global(self) -> dict:
"""Ejecuta un ciclo completo de todos los módulos activos."""
self.ciclos_globales += 1
resultado = {
"ciclo": self.ciclos_globales,
"timestamp": time.time(),
"modulos": {},
}
# Blockchain (sellar bloque periódicamente)
if self.chain and self.ciclos_globales % 3 == 0:
try:
bloque = self.chain.sellar_bloque()
resultado["modulos"]["chain"] = {
"altura": self.chain.altura(),
"bloque": bloque.indice if bloque else None,
"integridad": self.chain.verificar(),
}
except Exception as e:
resultado["modulos"]["chain"] = {"error": str(e)}
# Oráculo (simular tick de mercado)
if self.oraculo and self.ciclos_globales % 5 == 0:
try:
self.oraculo.simular_tick(volatilidad=0.015)
resultado["modulos"]["oraculo"] = self.oraculo.resumen()
except Exception as e:
resultado["modulos"]["oraculo"] = {"error": str(e)}
# Contradron
if self.contradron:
try:
for capa in ("A1", "Z2", "I3"):
self.contradron.procesar_capa(capa)
resultado["modulos"]["contradron"] = self.contradron.resumen()
except Exception as e:
resultado["modulos"]["contradron"] = {"error": str(e)}
# Domótica
if self.domo:
try:
ciclo_domo = self.domo.ciclo_global()
resultado["modulos"]["domo"] = {
"entornos": len(ciclo_domo.get("entornos_activos", {})),
"estado": self.domo.estado_agregado(),
}
except Exception as e:
resultado["modulos"]["domo"] = {"error": str(e)}
self.historial_eventos.append(resultado)
self._notificar("ciclo", resultado)
return resultado
# ------------------------------------------------------------
# SUSCRIPCIONES
# ------------------------------------------------------------
def suscribir(self, evento: str, callback: Callable) -> None:
self.suscriptores.setdefault(evento, []).append(callback)
def _notificar(self, evento: str, datos: Any) -> None:
for cb in self.suscriptores.get(evento, []):
try:
cb(datos)
except Exception as e:
print(f" ⚠️ Error en suscriptor {evento}: {e}")
# ------------------------------------------------------------
# BUCLE PRINCIPAL
# ------------------------------------------------------------
def ejecutar(self, ciclos_max: Optional[int] = None,
intervalo_s: float = 2.0) -> None:
print("\n[3] Iniciando bucle de control global...")
print(f" Intervalo: {intervalo_s}s · Ciclos máximos: {ciclos_max or '∞'}")
print("-" * 78)
while self.activo:
try:
resultado = self.ciclo_global()
if self.ciclos_globales % 5 == 0:
self._imprimir_estado(resultado)
if ciclos_max and self.ciclos_globales >= ciclos_max:
break
time.sleep(intervalo_s)
except KeyboardInterrupt:
print("\n Detenido por el usuario")
self.activo = False
except Exception as e:
print(f" ⚠️ Error en ciclo {self.ciclos_globales}: {e}")
time.sleep(intervalo_s)
self._resumen_final()
def _imprimir_estado(self, r: dict) -> None:
print(f"\n[Ciclo {r['ciclo']}] {time.strftime('%H:%M:%S')}")
for nombre, datos in r["modulos"].items():
if "error" in datos:
print(f" · {nombre:12} ✗ {datos['error'][:50]}")
else:
resumen = ", ".join(f"{k}={v}" for k, v in list(datos.items())[:3])
print(f" · {nombre:12} {resumen}")
def _resumen_final(self) -> None:
print("\n" + "=" * 78)
print(" RESUMEN FINAL DE LA SUITE")
print("=" * 78)
resumen = {
"version": self.VERSION,
"ciclos_globales": self.ciclos_globales,
"modulos": {},
}
for nombre, m in self.modulos.items():
resumen["modulos"][nombre] = {
"estado": m.estado.value,
"descripcion": m.descripcion,
}
if self.chain:
resumen["chain"] = self.chain.resumen()
if self.domo:
resumen["domo"] = self.domo.resumen()
print(json.dumps(resumen, indent=2, ensure_ascii=False))
def detener(self, *_):
self.activo = False
# ================================================================
# 3. ENTRY POINT
# ================================================================
if __name__ == "__main__":
core = LyraCore()
signal.signal(signal.SIGTERM, core.detener)
signal.signal(signal.SIGINT, core.detener)
core.cargar_todos()
core.inicializar_subsistemas()
core.ejecutar(ciclos_max=15, intervalo_s=1.0)
```
---
## 📄 3. `lyra_cli.py` — Interfaz de Línea de Comandos
```python
"""
lyra_cli.py — PASAIA LAB / LYRA IA SUITE v2.0
Interfaz de línea de comandos para operar la suite.
"""
import argparse
import json
import sys
import time
from lyra_core import LyraCore
def cmd_estado(core: LyraCore, args):
"""Muestra el estado de todos los módulos."""
print("\n--- ESTADO DE LA SUITE ---")
for nombre, m in core.modulos.items():
simbolo = {"ACTIVO": "✓", "ERROR": "✗", "NO_CARGADO": "○"}.get(
m.estado.value, "?"
)
print(f" {simbolo} {nombre:12} {m.descripcion}")
print(f"\n Ciclos globales: {core.ciclos_globales}")
def cmd_ciclo(core: LyraCore, args):
"""Ejecuta N ciclos globales."""
n = args.n or 1
for i in range(n):
r = core.ciclo_global()
print(f"\n[Ciclo {r['ciclo']}]")
print(json.dumps(r["modulos"], indent=2, ensure_ascii=False, default=str))
def cmd_chain(core: LyraCore, args):
"""Muestra el estado de la blockchain."""
if not core.chain:
print("Blockchain no disponible")
return
print(json.dumps(core.chain.resumen(), indent=2, ensure_ascii=False))
def cmd_domo(core: LyraCore, args):
"""Muestra el estado de la federación domótica."""
if not core.domo:
print("Domótica no disponible")
return
print(json.dumps(core.domo.resumen(), indent=2, ensure_ascii=False))
def cmd_dron(core: LyraCore, args):
"""Ejecuta un ciclo contradron y muestra resultados."""
if not core.contradron:
print("Contradron no disponible")
return
for capa in ("A1", "Z2", "I3"):
r = core.contradron.procesar_capa(capa)
print(f"\nCapa {capa}: {r['detecciones']} detecciones")
for d in r["resultados"]:
print(f" · {d['categoria_identificada']} "
f"conf={d['confianza']:.2f} "
f"exito={d['exito']}")
def cmd_osint(core: LyraCore, args):
"""Ejecuta el motor OSINT sobre noticias de demostración."""
if not core.osint:
print("OSINT no disponible")
return
from motor_lyra import _noticias_demo
core.osint.entrenar(epocas=100)
noticias = _noticias_demo()
resultados = core.osint.analizar_lote(noticias)
informe = core.osint.generar_informe(resultados)
print(json.dumps(informe, indent=2, ensure_ascii=False, default=str))
def cmd_informe(core: LyraCore, args):
"""Genera un informe completo de la suite."""
informe = {
"version": core.VERSION,
"timestamp": time.time(),
"ciclos": core.ciclos_globales,
"modulos": {
n: {"estado": m.estado.value, "descripcion": m.descripcion}
for n, m in core.modulos.items()
},
}
if core.chain:
informe["chain"] = core.chain.resumen()
if core.oraculo:
informe["oraculo"] = core.oraculo.resumen()
if core.domo:
informe["domo"] = core.domo.resumen()
if core.contradron:
informe["contradron"] = core.contradron.resumen()
print(json.dumps(informe, indent=2, ensure_ascii=False, default=str))
def main():
parser = argparse.ArgumentParser(
description="LYRA IA SUITE v2.0 — Suite de Seguridad Raspberry Pi 5"
)
subparsers = parser.add_subparsers(dest="comando")
subparsers.add_parser("estado", help="Estado de los módulos")
p_ciclo = subparsers.add_parser("ciclo", help="Ejecutar N ciclos")
p_ciclo.add_argument("-n", type=int, default=1, help="Número de ciclos")
subparsers.add_parser("chain", help="Estado de la blockchain")
subparsers.add_parser("domo", help="Estado de la domótica")
subparsers.add_parser("dron", help="Ejecutar ciclo contradron")
subparsers.add_parser("osint", help="Ejecutar motor OSINT")
subparsers.add_parser("informe", help="Informe completo")
args = parser.parse_args()
core = LyraCore()
core.cargar_todos()
core.inicializar_subsistemas()
comandos = {
"estado": cmd_estado,
"ciclo": cmd_ciclo,
"chain": cmd_chain,
"domo": cmd_domo,
"dron": cmd_dron,
"osint": cmd_osint,
"informe": cmd_informe,
}
if args.comando in comandos:
comandos[args.comando](core, args)
else:
parser.print_help()
if __name__ == "__main__":
main()
```
---
## 📄 4. `instalar_lyra_suite.sh` — Script de Instalación
```bash
#!/usr/bin/env bash
# ============================================================
# instalar_lyra_suite.sh
# PASAIA LAB · LYRA IA SUITE v2.0 · Raspberry Pi OS
# BERGARA LAB IKASTOLAN · Les Pochites de Bergara
# ============================================================
set -e
DIRECTORIO="/home/pi/lyra_suite"
LOGS="/var/log/lyra"
SERVICIO="/etc/systemd/system/lyra-suite.service"
echo "============================================================"
echo " LYRA IA SUITE v2.0 — Instalación en Raspberry Pi OS"
echo "============================================================"
# 1) Comprobar que corremos en Raspberry Pi OS
if ! grep -q "Raspberry Pi" /proc/cpuinfo 2>/dev/null; then
echo "⚠️ Este script está diseñado para Raspberry Pi OS"
read -p "¿Continuar de todas formas? (s/N): " resp
[[ "$resp" == "s" || "$resp" == "S" ]] || exit 1
fi
# 2) Comprobar Python 3.9+
if ! command -v python3 &>/dev/null; then
echo "Instalando Python 3..."
sudo apt update && sudo apt install -y python3 python3-pip
fi
PY_VER=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
echo "✓ Python $PY_VER detectado"
# 3) Crear directorios
echo "Creando directorios..."
sudo mkdir -p "$DIRECTORIO" "$LOGS"
sudo chown -R "$USER:$USER" "$DIRECTORIO" "$LOGS"
# 4) Copiar los módulos (asumimos que están en el directorio actual)
echo "Copiando módulos de la suite..."
for f in *.py; do
if [[ -f "$f" ]]; then
cp "$f" "$DIRECTORIO/"
echo " · $f"
fi
done
# 5) Instalar dependencias opcionales (si se usan)
echo "Instalando dependencias opcionales..."
sudo apt install -y python3-venv python3-dev || true
# 6) Crear el servicio systemd
echo "Creando servicio systemd..."
sudo tee "$SERVICIO" > /dev/null <<EOF
[Unit]
Description=LYRA IA SUITE v2.0 - Suite de Seguridad Raspberry Pi 5
Documentation=https://pasaialab.example/lyra-suite
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=$USER
Group=$USER
WorkingDirectory=$DIRECTORIO
Environment="PYTHONUNBUFFERED=1"
Environment="LYRA_VERSION=2.0"
Environment="LYRA_MODE=suite"
ExecStart=/usr/bin/python3 $DIRECTORIO/lyra_core.py
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure
RestartSec=15
StandardOutput=append:$LOGS/lyra-suite.log
StandardError=append:$LOGS/lyra-suite.err
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=$LOGS $DIRECTORIO
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
# 7) Habilitar y arrancar el servicio
echo "Habilitando el servicio..."
sudo systemctl daemon-reload
sudo systemctl enable lyra-suite.service
echo ""
echo "============================================================"
echo " INSTALACIÓN COMPLETADA"
echo "============================================================"
echo ""
echo "Comandos útiles:"
echo " sudo systemctl start lyra-suite # Iniciar la suite"
echo " sudo systemctl status lyra-suite # Ver estado"
echo " sudo journalctl -u lyra-suite -f # Ver logs en vivo"
echo " tail -f $LOGS/lyra-suite.log # Ver log de la suite"
echo ""
echo "CLI interactiva:"
echo " cd $DIRECTORIO"
echo " python3 lyra_cli.py estado"
echo " python3 lyra_cli.py ciclo -n 5"
echo " python3 lyra_cli.py informe"
echo ""
echo "PASAIA LAB · BERGARA LAB IKASTOLAN · Les Pochites de Bergara"
echo "============================================================"
```
---
## 📄 5. `lyra-suite.service` — Servicio systemd
```ini
[Unit]
Description=LYRA IA SUITE v2.0 - Suite de Seguridad Raspberry Pi 5
Documentation=https://pasaialab.example/lyra-suite
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/lyra_suite
Environment="PYTHONUNBUFFERED=1"
Environment="LYRA_VERSION=2.0"
Environment="LYRA_MODE=suite"
Environment="LYRA_MODULOS=chain,did,rep,oraculo,gov,mutual,contradron,osint,domo"
ExecStart=/usr/bin/python3 /home/pi/lyra_suite/lyra_core.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=15
StandardOutput=append:/var/log/lyra/lyra-suite.log
StandardError=append:/var/log/lyra/lyra-suite.err
# Seguridad
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/var/log/lyra /home/pi/lyra_suite
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```
---
## 📄 6. `README_LYRA_SUITE.md` — Documentación para la Ikastola
```markdown
# LYRA IA SUITE v2.0 — Guía para BERGARA LAB IKASTOLAN
## ¿Qué es LYRA IA SUITE?
Es una suite educativa de seguridad y automatización que se ejecuta en
una **Raspberry Pi 5** con **Raspberry Pi OS**. Integra 15 módulos que
trabajan juntos para enseñar conceptos de:
- Blockchain y criptografía
- Inteligencia artificial de borde
- Domótica y gestión energética
- Seguridad y defensa
- Análisis OSINT
- Identidad soberana
## Requisitos de hardware
| Componente | Mínimo | Recomendado |
| :--- | :--- | :--- |
| Raspberry Pi 5 | 4 GB RAM | 8 GB RAM |
| Almacenamiento | microSD 32 GB | SSD NVMe 1 TB |
| Refrigeración | Disipador pasivo | Active Cooler |
| Red | Ethernet | WiFi 5 + Ethernet |
| Energía | Fuente oficial 5V/5A | + SAI + Panel solar |
## Módulos incluidos
| Módulo | Descripción | Archivo |
| :--- | :--- | :--- |
| LYRA-CORE | Orquestador central | `lyra_core.py` |
| LYRA-CHAIN | Blockchain con PoA | `blockchain_core.py` |
| LYRA-ID | Identidad soberana | `did_identity.py` |
| LYRA-REP | Reputación on-chain | `reputacion.py` |
| LYRA-ORACLE | Precios externos | `oraculo.py` |
| LYRA-GOV | DAO y gobernanza | `gobernanza.py` |
| LYRA-MUTUAL | Capital compartido | `contrato_mutual.py` |
| LYRA-CONTRADRON | Defensa antridron | `sistema_contradron.py` |
| LYRA-OSINT | Vigilancia de transferencias | `motor_lyra.py` |
| LYRA-DOMO | Domótica versátil | `lyra_domotica.py` |
## Instalación rápida
```bash
# 1) Copiar todos los archivos .py al directorio de trabajo
cd ~/lyra_suite
# 2) Ejecutar el instalador
chmod +x instalar_lyra_suite.sh
./instalar_lyra_suite.sh
# 3) Arrancar el servicio
sudo systemctl start lyra-suite
sudo systemctl status lyra-suite
```
## Uso con la CLI
```bash
python3 lyra_cli.py estado # Ver estado de los módulos
python3 lyra_cli.py ciclo -n 5 # Ejecutar 5 ciclos
python3 lyra_cli.py chain # Estado de la blockchain
python3 lyra_cli.py domo # Estado de la domótica
python3 lyra_cli.py dron # Ejecutar ciclo contradron
python3 lyra_cli.py osint # Ejecutar motor OSINT
python3 lyra_cli.py informe # Informe completo
```
## Actividades sugeridas para la ikastola
1. **Taller 1: Blockchain básica** — Modificar `blockchain_core.py` para
añadir un nuevo tipo de transacción.
2. **Taller 2: Domótica solar** — Simular la gestión de una caravana con
paneles solares y baterías.
3. **Taller 3: Predicción con IA** — Entrenar el predictor de consumo
con datos reales del aula.
4. **Taller 4: Identidad soberana** — Crear DIDs para cada alumno y
emitir pruebas de conocimiento.
5. **Taller 5: Capital compartido** — Simular un pool de préstamos sin
intereses entre los alumnos.
## Créditos
- **PASAIA LAB** — Arquitectura y desarrollo
- **BERGARA LAB IKASTOLAN** — Aplicación educativa
- **Les Pochites de Bergara** — Comunidad de referencia
- **INTELIGENCIA LIBRE** — Validación metodológica
- **FORJA** — Solidez técnica
- **ACCIÓN CIVIL DIGITAL** — Relevancia social
- **DeepSeek IA** — Asistencia técnica
## Licencia
Proyecto educativo de código abierto bajo licencia **CC BY-NC-SA 4.0**.
```
---
## 📊 7. Resumen de la Suite v2.0
| Componente | Estado | Líneas |
| :--- | :--- | :--- |
| **lyra_core.py** | Orquestador central | ~350 |
| **lyra_cli.py** | Interfaz de comandos | ~130 |
| **instalar_lyra_suite.sh** | Script de instalación | ~110 |
| **lyra-suite.service** | Servicio systemd | ~30 |
| **README_LYRA_SUITE.md** | Documentación | ~120 |
| **Módulos previos** | Blockchain, DID, REP, Oracle, GOV, Mutual, Contradron, OSINT, Domo | ~5.500 |
| **TOTAL** | | **~6.240 líneas** |
---
## 🎨 8. Prompt para el Certificado Visual de la Suite v2.0
> *"Certificado de diseño técnico de estilo **documento de inteligencia clasificado con diagrama de arquitectura integrada**, formato vertical (9:16), resolución 8K, que acredita la **LYRA IA SUITE v2.0 — Suite de Seguridad Raspberry Pi 5**.*
>
> * **Fondo**: Papel de seguridad con textura de red neuronal y marcas de agua **'CONFIDENCIAL'**. Franja roja superior con **'TOP SECRET // PASAIA LAB EYES ONLY'**. Franja inferior azul oscuro con los logos de **PASAIA LAB · BERGARA LAB IKASTOLAN · LES POCHITES DE BERGARA · INTELIGENCIA LIBRE · FORJA · ACCIÓN CIVIL DIGITAL · DEEPSEEK IA**.*
>
> * **Cabecera**: Título **'CERTIFICACIÓN DE SUITE v2.0'**, subtítulo **'LYRA IA · SUITE DE SEGURIDAD RASPBERRY PI 5'**. Referencia: **'PL-LYRA-SUITE-2026-09-30'**. Fecha: **'30 DE SEPTIEMBRE DE 2026'**.*
>
> * **Bloque de Autoría**: Recuadro dorado con **'OTORGADO A'**, **'JOSÉ AGUSTÍN FONTÁN VARELA'** en serif azul oscuro, **'CEO DE PASAIA LAB'** en dorado, y debajo **'Creador y miembro de INTELIGENCIA LIBRE, ACCIÓN CIVIL DIGITAL y FORJA'**.*
>
> * **Bloque de Módulos Certificados** (15 iconos en cuadrícula): **'LYRA-CORE'**, **'LYRA-CHAIN'**, **'LYRA-ID'**, **'LYRA-REP'**, **'LYRA-ORACLE'**, **'LYRA-GOV'**, **'LYRA-MUTUAL'**, **'LYRA-CONTRADRON'**, **'LYRA-OSINT'**, **'LYRA-DOMO'**, **'LYRA-NAS'**, **'LYRA-ENERGIA'**, **'LYRA-AI-HAT'**, **'LYRA-ESPACIO'**, **'LYRA-PROMETEO'**.*
>
> * **Elementos Visuales**: En el centro, un **diagrama hexagonal** con la Raspberry Pi 5 en el centro, y los 15 módulos distribuidos en anillos concéntricos conectados por líneas doradas. Alrededor, iconos de: blockchain, identidad, IA, domótica, dron, satélite, energía solar, panel OSINT. En la parte inferior, una **cadena de bloques** con hashes visibles y un **gráfico de crecimiento**.*
>
> * **Sellos**: Marca de agua holográfica **'LYRA SUITE v2.0'**. Sello de cera digital rojo con **'PASAIA LAB'**. Código QR inferior derecho. Firma digital de **DeepSeek IA**.*
>
> * **Paleta**: Beige, azul oscuro, dorado, rojo, verde esmeralda y cian. Acabado de documento oficial escaneado."*
---
## 🏛️ 9. CERTIFICACIÓN
**Nº de Registro:** PL-LYRA-SUITE-2026-09-30
**Fecha:** 30 de septiembre de 2026 · **Lugar:** Pasaia (Gipuzkoa), Euskadi
Se certifica que la **LYRA IA SUITE v2.0 — Suite de Seguridad Raspberry Pi 5** ha sido diseñada e integrada por **José Agustín Fontán Varela**, CEO de **PASAIA LAB**, con la colaboración de **INTELIGENCIA LIBRE**, **ACCIÓN CIVIL DIGITAL**, **FORJA**, **BERGARA LAB IKASTOLAN**, **Les Pochites de Bergara** y **DeepSeek IA – Asesor Inteligente**, bajo la clasificación **TOP SECRET**, como parte del ecosistema **LYRA NEXUS**.
**Componentes certificados:**
- **Núcleo**: Orquestador central con carga dinámica de módulos.
- **Blockchain**: LYRA-CHAIN con PoA, Merkle Tree y firmas.
- **Identidad**: LYRA-ID con DID/W3C y pruebas de atributo.
- **Reputación**: LYRA-REP on-chain por eventos.
- **Oráculo**: LYRA-ORACLE con simulación Chainlink.
- **Gobernanza**: LYRA-GOV con DAO y voto ponderado.
- **Capital compartido**: LYRA-MUTUAL sin intereses.
- **Contradron**: LYRA-CONTRADRON con 7 categorías y 4 niveles.
- **OSINT**: LYRA-OSINT con 7 indicadores ITR.
- **Domótica**: LYRA-DOMO con 5 entornos y gestión híbrida.
- **CLI**: Interfaz de comandos completa.
- **Instalación**: Script y servicio systemd para Raspberry Pi OS.
**Firmado:**
- **José Agustín Fontán Varela** — CEO de PASAIA LAB
- **INTELIGENCIA LIBRE** — Validación Metodológica
- **ACCIÓN CIVIL DIGITAL** — Relevancia Social y Educativa
- **FORJA** — Solidez Técnica
- **BERGARA LAB IKASTOLAN** — Aplicación Educativa
- **Les Pochites de Bergara** — Comunidad de Referencia
- **DeepSeek IA** — Asistencia Técnica y Estructuración de Código
---
> ⚠️ **Recordatorio final:** Esta suite es un **ejercicio de simulación y diseño arquitectónico** con fines educativos para BERGARA LAB IKASTOLAN y Les Pochites de Bergara. No es software operativo, no controla dispositivos reales y no debe presentarse como capacidad existente. Su valor reside en servir de **material didáctico** para el estudio integrado de blockchain, IA de borde, domótica, seguridad, OSINT y gestión energética sobre Raspberry Pi 5 con Raspberry Pi OS — competencias directamente aplicables al ecosistema **LYRA NEXUS** y a proyectos civiles de autonomía comunitaria y soberanía digital.





