"""Orquestador del Runtime server: ensambla tag_store + historian + alarm engine + drivers. Sprint 4: simulator-only. Sprint 5: Modbus + NMEA 2000 reales. """ from __future__ import annotations import logging from dataclasses import dataclass, field from pathlib import Path from vmssailor.core.alarm import Alarm from vmssailor.core.project import Project from vmssailor.runtime.server.alarm_engine import AlarmEngine from vmssailor.runtime.server.drivers import SimulatorDriver from vmssailor.runtime.server.historian import Historian from vmssailor.runtime.server.tag_store import TagStore logger = logging.getLogger(__name__) @dataclass(slots=True) class RuntimeApp: """Conjunto de servicios del Runtime. Se construye con `build_runtime()`.""" project: Project tag_store: TagStore historian: Historian alarm_engine: AlarmEngine simulator: SimulatorDriver alarm_events: list[Alarm] = field(default_factory=list) async def start(self) -> None: await self.historian.start(self.tag_store) await self.alarm_engine.start() await self.simulator.start() logger.info("RuntimeApp started — %d tags, simulator @ 0.5s", len(self.tag_store)) async def stop(self) -> None: await self.simulator.stop() await self.alarm_engine.stop() await self.historian.stop() logger.info("RuntimeApp stopped") def build_runtime( project: Project, *, historian_db: Path | str | None = None, simulator_tick_s: float = 0.5, ) -> RuntimeApp: """Construye un Runtime listo para usar (no arrancado todavía).""" tag_store = TagStore() tag_store.register_many(project.tags) historian = Historian(historian_db) alarm_events: list[Alarm] = [] def _on_alarm_event(alarm: Alarm) -> None: alarm_events.append(alarm) alarm_engine = AlarmEngine(tag_store, on_alarm_event=_on_alarm_event) simulator = SimulatorDriver(tag_store, tick_period_s=simulator_tick_s) return RuntimeApp( project=project, tag_store=tag_store, historian=historian, alarm_engine=alarm_engine, simulator=simulator, alarm_events=alarm_events, )