import random from datetime import datetime, timezone, timedelta from bots.base import BaseBot class AtsBot(BaseBot): """Automatic Transfer Switch — monitors which utility feed is active and logs transfers.""" interval = 30 def __init__(self, site_id: str, ats_id: str) -> None: super().__init__() self.site_id = site_id self.ats_id = ats_id self._active_feed = "utility-a" self._transfer_count = 0 self._last_transfer = None # ISO string or None self._transfer_ms = None # last transfer time in ms self._transferring = False def get_topic(self) -> str: return f"bms/{self.site_id}/power/ats/{self.ats_id}" def set_scenario(self, name: str | None) -> None: super().set_scenario(name) if name == "ATS_TRANSFER": # Simulate a transfer to generator / utility-b self._active_feed = "generator" self._transfer_count += 1 self._transfer_ms = round(random.uniform(80, 200)) # typical ATS 80–200 ms self._last_transfer = datetime.now(timezone.utc).isoformat() self._transferring = True elif name in (None, "RESET"): self._active_feed = "utility-a" self._transferring = False def get_payload(self) -> dict: # Utility voltage sensing (slight variation on active feed) ua_v = 415.0 + random.gauss(0, 1.0) if self._active_feed == "utility-a" else 0.0 ub_v = 415.0 + random.gauss(0, 1.0) if self._active_feed == "utility-b" else 415.0 + random.gauss(0, 0.5) gen_v = 415.0 + random.gauss(0, 1.5) if self._active_feed == "generator" else 0.0 return { "state": "transferring" if self._transferring else "stable", "active_feed": self._active_feed, "transfer_count": self._transfer_count, "last_transfer_at": self._last_transfer, "last_transfer_ms": self._transfer_ms, "utility_a_v": round(ua_v, 1), "utility_b_v": round(ub_v, 1), "generator_v": round(gen_v, 1), }