Fix NA Ingest's own DVS from the DANTE button, and stop saying NOTHING TO FIX when something is failing.

STUDIO-A-Ingest now maps to a local dvs_ingest fix (same helper as the other
Macs, which NA Ingest also needs). A hold on a failing button that has no
automatic fix now shows NO AUTO FIX instead of NOTHING TO FIX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 12:19:26 -04:00
co-authored by Claude Opus 5.5
parent ef9d755982
commit b8748be655
4 changed files with 31 additions and 4 deletions
+3 -1
View File
@@ -42,6 +42,7 @@
"dvs_prop": { "host": "prop", "short": "DVS", "label": "start Dante Virtual Soundcard on the ProPresenter Mac", "run": "sudo -n /usr/local/sbin/status-panel-dvs-start && open -a 'Dante Virtual Soundcard'" },
"dvs_tracks": { "host": "tracks", "short": "DVS", "label": "start Dante Virtual Soundcard on the Tracks Mac", "run": "sudo -n /usr/local/sbin/status-panel-dvs-start && open -a 'Dante Virtual Soundcard'" },
"dvs_translation": { "host": "translation", "short": "DVS", "label": "start Dante Virtual Soundcard on NA Translation", "run": "sudo -n /usr/local/sbin/status-panel-dvs-start && open -a 'Dante Virtual Soundcard'" },
"dvs_ingest": { "kind": "local", "short": "DVS", "label": "start Dante Virtual Soundcard on NA Ingest", "run": "sudo -n /usr/local/sbin/status-panel-dvs-start && open -a 'Dante Virtual Soundcard'" },
"bridge": { "kind": "local", "short": "BRIDGE", "label": "restart the Resi bridge",
"run": "launchctl kickstart -k gui/$(id -u)/org.waterschurch.resi-propresenter || launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/org.waterschurch.resi-propresenter.plist" },
"captions": { "kind": "local", "short": "CAPTIONS", "label": "restart lobby captions",
@@ -70,7 +71,8 @@
{ "id": "x32", "label": "X32", "pos": [2, 1], "checks": [{ "type": "conn", "conn": "x32" }] },
{ "id": "dante", "label": "DANTE", "pos": [2, 2], "checks": [
{ "type": "dante", "conn": "audinate-dantecontroller",
"fix": { "NA-ProPresenter-Mac": "dvs_prop", "NA-Tracks": "dvs_tracks", "NA-Translation": "dvs_translation" },
"fix": { "NA-ProPresenter-Mac": "dvs_prop", "NA-Tracks": "dvs_tracks", "NA-Translation": "dvs_translation",
"STUDIO-A-Ingest": "dvs_ingest" },
"devices": {
"FOH-DiGiCo-DMI-1": "DMI-1", "FOH-DiGiCo-DMI-2": "DMI-2", "BOH-WING": "WING", "BOH-DQ-Rack": "DQ RACK",
"BOH-AD4Q-A": "AD4Q-A", "BOH-AD4Q-B": "AD4Q-B", "STUDIO-A-X32": "STA X32",
+1 -1
View File
@@ -1,4 +1,4 @@
# Paste into Apple Remote Desktop: select NA ProPresenter Mac, NA Tracks, NA Translation ->
# Paste into Apple Remote Desktop: select NA ProPresenter Mac, NA Tracks, NA Translation, NA Ingest ->
# Manage -> Send UNIX Command -> "Run command as: User: root" -> Send.
#
# Lets the status panel start Dante Virtual Soundcard's audio engine, which needs admin rights:
+14 -2
View File
@@ -754,6 +754,14 @@ class Engine:
plan.append((ident, "restart", chk["conn"], chk))
return plan
def failing(self, tile_id):
"""Is anything on this button (or its members) in a confirmed fault right now?"""
for key in self.keys_for(tile_id):
tr = self.trackers[key]
if tr.confirmed and tr.result.level in (WARN, ERR):
return True
return False
def note(self, tile_id, text, level, now, seconds):
"""Show `text` on the button for a while (hold feedback), instead of its usual text."""
self.notes[tile_id] = {"text": text, "level": level, "until": now + seconds}
@@ -761,8 +769,12 @@ class Engine:
def run_fixes(self, tile_id, snap, comp, now, cooldown=60):
plan = self.fix_plan(tile_id, snap)
if not plan:
log.info("HOLD %s: nothing failing, nothing to fix", tile_id)
self.note(tile_id, "NOTHING\nTO FIX", "idle", now, 4)
if self.failing(tile_id):
log.info("HOLD %s: failing, but there is no automatic fix for it", tile_id)
self.note(tile_id, "NO AUTO\nFIX", "idle", now, 4)
else:
log.info("HOLD %s: nothing failing, nothing to fix", tile_id)
self.note(tile_id, "NOTHING\nTO FIX", "idle", now, 4)
return plan
started, names, waited = [], [], False
for ident, kind, what, chk in plan:
+13
View File
@@ -530,6 +530,19 @@ class TestFixes(unittest.TestCase):
tiles = self.engine.step(self.snap, time.time())
self.assertEqual((tiles["dante"]["x"], level(tiles["dante"])), ("DANTE\nFIX FAILED\nDVS", "failed"))
def test_ingest_dvs_and_no_auto_fix(self):
devices = json.loads(self.snap.vars[("audinate-dantecontroller", "devices")])
devices.remove("STUDIO-A-Ingest")
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
self.assertEqual(self.plan("dante"), [("fix", "dvs_ingest")])
# A failure with no fix (a console) must not claim there is nothing wrong.
devices.append("STUDIO-A-Ingest")
devices.remove("BOH-WING")
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
_, t = run_steps(self.engine, self.snap, SUNDAY, 4)
self.engine.run_fixes("dante", self.snap, None, t)
self.assertEqual(self.engine.notes["dante"]["text"], "NO AUTO\nFIX")
def test_hold_on_a_green_button_says_so(self):
_, t = run_steps(self.engine, self.snap, SUNDAY, 2)
self.engine.run_fixes("x32", self.snap, None, t)