Resi: checks keep quiet while a Resi event starts or stops (weekly schedule + PCO special services)

User 2026-10-26: three services each have a Resi event that starts and stops on its own; the cloud,
decoder and Resi audio checks threw false alarms then. resi_events (weekly, from studio.resi.io) and the
special services' times from PCO; checks marked quiet resi_events show OK (EVENT CHANGE) within 10 min of
an event's start or end. The encoder's ping and web checks still alarm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 12:37:00 -04:00
co-authored by Claude Opus 5.5
parent 8b9a71eba0
commit aa90f7e03c
5 changed files with 149 additions and 7 deletions
+36 -1
View File
@@ -1421,7 +1421,8 @@ class Engine:
def evaluate(self, snap, now, service_on):
ctx = {"now": now, "service": service_on, "any_recording": False, "dante_all": {},
"ready_due": in_windows(self.ready_cfg.get("due", []), now), "ready_done": self.ready_done(now),
"bypassed": self.bypass_names()[0], "bypassed_fixes": self.bypass_fixes(), "autofix_windows": (self.cfg.get("auto_fix") or {}).get("windows", [])}
"bypassed": self.bypass_names()[0], "bypassed_fixes": self.bypass_fixes(),
"resi_quiet": resi_quiet(self.cfg, now), "autofix_windows": (self.cfg.get("auto_fix") or {}).get("windows", [])}
for t in all_tiles(self.cfg):
for chk in t.get("checks", []):
if chk["type"] == "dante":
@@ -1439,6 +1440,8 @@ class Engine:
results = CHECKS[chk["type"]](chk, snap, ctx)
if isinstance(chk.get("fix"), str) and chk["fix"] in ctx["bypassed_fixes"]:
results = [(sub, Result(OK)) for sub, _ in results] # switched off by its bypass key
if chk.get("quiet") == "resi_events" and ctx.get("resi_quiet"):
results = [(sub, Result(OK, info="EVENT CHANGE")) for sub, _ in results]
except Exception as e: # a bad check must not take the panel down
log.exception("check %s/%s failed", t["id"], chk["type"])
results = [("error", Result(WARN, "CHECK BUG"))]
@@ -3497,6 +3500,38 @@ class AtemWatcher:
ATEM_WATCHER = None
def resi_event_edges(cfg, now):
"""Start and end times (unix) of the Resi events around `now`: the weekly ones in config "resi_events" and
the special services PCO lists (readiness.LAST["resi_specials"], fetched with the READY page)."""
re_ = cfg.get("resi_events") or {}
edges = []
d0 = datetime.fromtimestamp(now)
for back in (1, 0, -1):
day = datetime(d0.year, d0.month, d0.day) - timedelta(days=back)
for w in re_.get("weekly") or []:
if day.strftime("%a").lower()[:3] not in w.get("days", []):
continue
for k in ("start", "end"):
h, m = (int(x) for x in w[k].split(":"))
edges.append(time.mktime((day + timedelta(hours=h, minutes=m)).timetuple()))
if re_.get("pco_specials", True):
try:
import readiness
edges += [t for ev in readiness.LAST.get("resi_specials") or [] for t in ev]
except Exception: # noqa: BLE001 - no READY page here
pass
return edges
def resi_quiet(cfg, now):
"""True within "margin_minutes" (10) of a Resi event starting or stopping: the cloud, the decoder and the
Resi audio change over then, and those checks keep quiet (2026-10-26: false alarms at every event change)."""
if not cfg.get("resi_events"):
return False
margin = (cfg["resi_events"].get("margin_minutes", 10)) * 60
return any(abs(now - t) <= margin for t in resi_event_edges(cfg, now))
def check_atem(chk, snap, ctx):
"""chk["part"] "audio" or "camera": the switcher must match the restore file. "silence": a metered input
(Resi) has had no audio at all for a while; only while a HyperDeck records (a service is on): between services