Tell a dead device, a failed connection and a disabled connection apart.

Ping failures now read NO PING, Companion connection errors OFFLINE, and a
watched connection that is disabled in Companion shows amber DISABLED instead
of going quietly grey.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 10:29:50 -04:00
co-authored by Claude Opus 5.5
parent 1f2c5719fb
commit 51bd44f9a0
3 changed files with 15 additions and 6 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ The **page number key** on every page follows the ALL button. It's green when ev
| | HD2 and HD4 are `"optional": true` in `config.json`: with no disk they sit grey with no alarm, and once a disk is in they are watched like the others. Add or remove `"optional": true` on any deck to change that. | | | HD2 and HD4 are `"optional": true` in `config.json`: with no disk they sit grey with no alarm, and once a disk is in they are watched like the others. Add or remove `"optional": true` on any deck to change that. |
| TASCAM | connection; the recorder's own Error / Caution | | TASCAM | connection; the recorder's own Error / Caution |
| X32, ATEM, ARENA, OBS | Companion connection | | X32, ATEM, ARENA, OBS | Companion connection |
| LED | VX1000 and UHD Jr: Companion connection **and** each one answers ping (the NovaStar module keeps saying "Connected" after a processor is switched off) | | LED | VX1000 and UHD Jr: Companion connection **and** each one answers ping (the NovaStar module keeps saying "Connected" after a processor is switched off). "UHDJR NO PING" = processor off or unreachable; "UHDJR OFFLINE" = Companion's connection failed; "UHDJR DISABLED" (amber) = connection turned off in Companion. |
| DANTE | All 19 Dante devices ("19/19"), named when one drops: "WING GONE", "TRACKS GONE", "PROP MAC GONE". | | DANTE | All 19 Dante devices ("19/19"), named when one drops: "WING GONE", "TRACKS GONE", "PROP MAC GONE". |
| MIDI | Lighting PC and SuperRack still joined to NA Ingest's network MIDI session; the Lighting PC and NA Tracks MIDI sessions still on the network. A clean disconnect shows within seconds; a crash or pulled cable takes about a minute (macOS's own timeout, measured). | | MIDI | Lighting PC and SuperRack still joined to NA Ingest's network MIDI session; the Lighting PC and NA Tracks MIDI sessions still on the network. A clean disconnect shows within seconds; a crash or pulled cable takes about a minute (macOS's own timeout, measured). |
| APPS | ProPresenter API; Ableton OSC; tracks Mac pings; Bible TV app answering on :8080 (every 5 s); Bible TV OSC. Messages name the app ("PROPRES OFFLINE", "BIBLE APP DOWN"). Hold 2 s restarts the ProPresenter, Ableton and Bible TV Companion connections. | | APPS | ProPresenter API; Ableton OSC; tracks Mac pings; Bible TV app answering on :8080 (every 5 s); Bible TV OSC. Messages name the app ("PROPRES OFFLINE", "BIBLE APP DOWN"). Hold 2 s restarts the ProPresenter, Ableton and Bible TV Companion connections. |
+3 -2
View File
@@ -166,7 +166,8 @@ def conn_result(snap, label, now, service_only=False):
if c is None: if c is None:
return Result(ERR, "NOT IN COMPANION", service_only=service_only) return Result(ERR, "NOT IN COMPANION", service_only=service_only)
if not c.get("enabled"): if not c.get("enabled"):
return Result(OFF, info="DISABLED") # Everything on the page is expected on; a disabled connection is a warning, not silence.
return Result(WARN, "DISABLED")
cat = c.get("category") cat = c.get("category")
if cat == "good": if cat == "good":
return Result(OK) return Result(OK)
@@ -345,7 +346,7 @@ def check_tascam(chk, snap, ctx):
def check_ping(chk, snap, ctx): def check_ping(chk, snap, ctx):
fails = snap.ping.get(chk["host"]) fails = snap.ping.get(chk["host"])
if fails is not None and fails >= chk.get("failures", 2): if fails is not None and fails >= chk.get("failures", 2):
msg = chk.get("msg") or chk.get("name", chk["host"]) + " OFFLINE" msg = chk.get("msg") or chk.get("name", chk["host"]) + " NO PING"
return [("ping", Result(ERR, msg, service_only=chk.get("service_only", False), named=True))] return [("ping", Result(ERR, msg, service_only=chk.get("service_only", False), named=True))]
return [("ping", Result(OK))] return [("ping", Result(OK))]
+11 -3
View File
@@ -109,7 +109,8 @@ class TestChecks(unittest.TestCase):
c["message"] = "connect EHOSTUNREACH" c["message"] = "connect EHOSTUNREACH"
self.assertEqual(sp.conn_result(self.snap, "ATEM", self.now).msg, "UNREACHABLE") self.assertEqual(sp.conn_result(self.snap, "ATEM", self.now).msg, "UNREACHABLE")
c["enabled"] = False c["enabled"] = False
self.assertEqual(sp.conn_result(self.snap, "ATEM", self.now).level, sp.OFF) self.assertEqual((sp.conn_result(self.snap, "ATEM", self.now).level,
sp.conn_result(self.snap, "ATEM", self.now).msg), (sp.WARN, "DISABLED"))
self.assertEqual(sp.conn_result(self.snap, "nope", self.now).msg, "NOT IN COMPANION") self.assertEqual(sp.conn_result(self.snap, "nope", self.now).msg, "NOT IN COMPANION")
self.assertEqual(sp.conn_result(self.snap, "x32", self.now + 60).msg, "NO DATA") self.assertEqual(sp.conn_result(self.snap, "x32", self.now + 60).msg, "NO DATA")
@@ -250,8 +251,15 @@ class TestChecks(unittest.TestCase):
# 2026-10-08: UHD Jr powered off, NovaStar module still "Connected". # 2026-10-08: UHD Jr powered off, NovaStar module still "Connected".
self.snap.ping["10.1.14.115"] = 2 self.snap.ping["10.1.14.115"] = 2
tiles, _ = run_steps(sp.Engine(CONFIG), self.snap, self.now, 4) tiles, _ = run_steps(sp.Engine(CONFIG), self.snap, self.now, 4)
self.assertEqual(tiles["led"]["x"], "LED\nUHDJR OFFLINE") self.assertEqual(tiles["led"]["x"], "LED\nUHDJR NO PING")
self.assertEqual(tiles["video"]["x"], "VIDEO\nUHDJR OFFLINE") self.assertEqual(tiles["video"]["x"], "VIDEO\nUHDJR NO PING")
self.snap.conns["UHDJr"]["category"] = "error" # and Companion's connection fails too
tiles, _ = run_steps(sp.Engine(CONFIG), self.snap, self.now, 4)
self.assertEqual(tiles["led"]["x"], "LED\nUHDJR OFFLINE\n+1")
self.snap.conns["UHDJr"]["category"], self.snap.conns["UHDJr"]["enabled"] = "good", False
self.snap.ping["10.1.14.115"] = 0
tiles, _ = run_steps(sp.Engine(CONFIG), self.snap, self.now, 4)
self.assertEqual((tiles["led"]["x"], level(tiles["led"])), ("LED\nUHDJR DISABLED", "warn"))
def test_ingest_services(self): def test_ingest_services(self):
del self.snap.launchd["org.waterschurch.resi-propresenter"] del self.snap.launchd["org.waterschurch.resi-propresenter"]