A DANTE hold on missing hardware restarts Companion's Dante module.
Dante Virtual Soundcard on the four Macs is restarted directly; for hardware (consoles, racks, cards, AVIOs) nothing can be restarted from here, so a hold re-checks via a fresh Dante module connection (harmless to audio and routing). If the device is still gone it is really off or unplugged. A check's fix can now be "restart-connection", and a fix map can use "*" for every other sub-check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -72,7 +72,7 @@
|
|||||||
{ "id": "dante", "label": "DANTE", "pos": [2, 2], "checks": [
|
{ "id": "dante", "label": "DANTE", "pos": [2, 2], "checks": [
|
||||||
{ "type": "dante", "conn": "audinate-dantecontroller",
|
{ "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" },
|
"STUDIO-A-Ingest": "dvs_ingest", "*": "restart-connection" },
|
||||||
"devices": {
|
"devices": {
|
||||||
"FOH-DiGiCo-DMI-1": "DMI-1", "FOH-DiGiCo-DMI-2": "DMI-2", "BOH-WING": "WING", "BOH-DQ-Rack": "DQ RACK",
|
"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",
|
"BOH-AD4Q-A": "AD4Q-A", "BOH-AD4Q-B": "AD4Q-B", "STUDIO-A-X32": "STA X32",
|
||||||
|
|||||||
+13
-3
@@ -452,6 +452,9 @@ CHECKS = {
|
|||||||
|
|
||||||
# Checks whose connection a long press may restart (Dante is shared, so not that one).
|
# Checks whose connection a long press may restart (Dante is shared, so not that one).
|
||||||
RESTARTABLE = ("conn", "hyperdeck", "shure", "psm", "tascam")
|
RESTARTABLE = ("conn", "hyperdeck", "shure", "psm", "tascam")
|
||||||
|
# A check's "fix" may name this instead of an entry in "fixes": restart its own Companion
|
||||||
|
# connection. The Dante button uses it for hardware, which cannot be restarted from here.
|
||||||
|
RESTART_CONNECTION = "restart-connection"
|
||||||
|
|
||||||
|
|
||||||
def needed_variables(cfg):
|
def needed_variables(cfg):
|
||||||
@@ -750,7 +753,13 @@ class Engine:
|
|||||||
continue
|
continue
|
||||||
fix_id = chk.get("fix")
|
fix_id = chk.get("fix")
|
||||||
if isinstance(fix_id, dict):
|
if isinstance(fix_id, dict):
|
||||||
fix_id = fix_id.get(sub)
|
fix_id = fix_id.get(sub, fix_id.get("*")) # "*": every other sub-check
|
||||||
|
if fix_id == RESTART_CONNECTION and chk.get("conn"):
|
||||||
|
ident = ("restart", chk["conn"]) # e.g. Companion's Dante module
|
||||||
|
if ident not in seen:
|
||||||
|
seen.add(ident)
|
||||||
|
plan.append((ident, "restart", chk["conn"], chk))
|
||||||
|
continue
|
||||||
if fix_id:
|
if fix_id:
|
||||||
if chk["type"] == "hyperdeck" and hyperdeck_recording(snap, chk["conn"]):
|
if chk["type"] == "hyperdeck" and hyperdeck_recording(snap, chk["conn"]):
|
||||||
continue
|
continue
|
||||||
@@ -1233,9 +1242,10 @@ def load_config(path):
|
|||||||
for c in t.get("checks", []):
|
for c in t.get("checks", []):
|
||||||
fixes = c.get("fix") if isinstance(c.get("fix"), dict) else {"": c.get("fix")}
|
fixes = c.get("fix") if isinstance(c.get("fix"), dict) else {"": c.get("fix")}
|
||||||
for f in fixes.values():
|
for f in fixes.values():
|
||||||
if f and f not in cfg.get("fixes", {}):
|
if f and f != RESTART_CONNECTION and f not in cfg.get("fixes", {}):
|
||||||
raise ValueError("tile %s: unknown fix %s" % (t["id"], f))
|
raise ValueError("tile %s: unknown fix %s" % (t["id"], f))
|
||||||
if f and cfg["fixes"][f].get("kind", "ssh") == "ssh" and cfg["fixes"][f]["host"] not in cfg.get("hosts", {}):
|
if (f and f != RESTART_CONNECTION and cfg["fixes"][f].get("kind", "ssh") == "ssh"
|
||||||
|
and cfg["fixes"][f]["host"] not in cfg.get("hosts", {})):
|
||||||
raise ValueError("fix %s: unknown host" % f)
|
raise ValueError("fix %s: unknown host" % f)
|
||||||
if c["type"] == "remote" and c["host"] not in cfg.get("hosts", {}):
|
if c["type"] == "remote" and c["host"] not in cfg.get("hosts", {}):
|
||||||
raise ValueError("tile %s: unknown host %s" % (t["id"], c["host"]))
|
raise ValueError("tile %s: unknown host %s" % (t["id"], c["host"]))
|
||||||
|
|||||||
@@ -461,9 +461,9 @@ class TestFixes(unittest.TestCase):
|
|||||||
def test_dante_reopens_dvs_on_the_right_mac(self):
|
def test_dante_reopens_dvs_on_the_right_mac(self):
|
||||||
devices = json.loads(self.snap.vars[("audinate-dantecontroller", "devices")])
|
devices = json.loads(self.snap.vars[("audinate-dantecontroller", "devices")])
|
||||||
devices.remove("NA-ProPresenter-Mac")
|
devices.remove("NA-ProPresenter-Mac")
|
||||||
devices.remove("BOH-WING") # no fix for a console
|
devices.remove("BOH-WING") # hardware: re-check via Companion's Dante module
|
||||||
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
|
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
|
||||||
self.assertEqual(self.plan("dante"), [("fix", "dvs_prop")])
|
self.assertEqual(self.plan("dante"), [("restart", "audinate-dantecontroller"), ("fix", "dvs_prop")])
|
||||||
|
|
||||||
def test_rec_reboots_only_hung_decks_not_recording_ones(self):
|
def test_rec_reboots_only_hung_decks_not_recording_ones(self):
|
||||||
for i in (2, 3, 5):
|
for i in (2, 3, 5):
|
||||||
@@ -543,13 +543,11 @@ class TestFixes(unittest.TestCase):
|
|||||||
devices.remove("STUDIO-A-Ingest")
|
devices.remove("STUDIO-A-Ingest")
|
||||||
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
|
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
|
||||||
self.assertEqual(self.plan("dante"), [("fix", "dvs_ingest")])
|
self.assertEqual(self.plan("dante"), [("fix", "dvs_ingest")])
|
||||||
# A failure with no fix (a console) must not claim there is nothing wrong.
|
# A failure with no fix must not claim there is nothing wrong.
|
||||||
devices.append("STUDIO-A-Ingest")
|
self.snap.midi["NA Ingest"]["peers"] = []
|
||||||
devices.remove("BOH-WING")
|
|
||||||
self.snap.vars[("audinate-dantecontroller", "devices")] = json.dumps(devices)
|
|
||||||
_, t = run_steps(self.engine, self.snap, SUNDAY, 4)
|
_, t = run_steps(self.engine, self.snap, SUNDAY, 4)
|
||||||
self.engine.run_fixes("dante", self.snap, None, t)
|
self.engine.run_fixes("midi", self.snap, None, t)
|
||||||
self.assertEqual(self.engine.notes["dante"]["text"], "NO AUTO\nFIX")
|
self.assertEqual(self.engine.notes["midi"]["text"], "NO AUTO\nFIX")
|
||||||
|
|
||||||
def test_hold_on_a_green_button_says_so(self):
|
def test_hold_on_a_green_button_says_so(self):
|
||||||
_, t = run_steps(self.engine, self.snap, SUNDAY, 2)
|
_, t = run_steps(self.engine, self.snap, SUNDAY, 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user