HyperDeck IPs from Companion, Vista Art-Net heartbeat, quiet Tascam module

- The hold-to-fix deck probe takes each HyperDeck's IP from its Companion
  connection's "ip" variable, so the config no longer repeats them.
- APPS shows "VISTA SILENT" when the Lighting PC's Art-Net poll (every 0.5 s)
  is not heard for 5 s: a crashed or closed Vista shows in seconds, not the
  minute macOS takes to drop a network MIDI peer.
- tascam-quiet/ builds the Tascam DA-6400 module 1.3.1-quiet: the recorder's
  "Illegal Status" warning is logged once a minute, not 5 times a second.
- README: hold-to-fix table fixed and updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 13:46:49 -04:00
co-authored by Claude Opus 5.5
parent d06798adf0
commit 77daf7424d
5 changed files with 186 additions and 17 deletions
+37 -2
View File
@@ -38,6 +38,7 @@ def healthy_snapshot(now):
snap.conns = {l: {"id": "id-" + l, "enabled": True, "category": "good", "message": None} for l in labels}
snap.conns_time = now
for i in range(1, 7):
snap.vars[("HyperDeck_%d" % i, "ip")] = "10.1.10.1%d" % i
snap.vars[("HyperDeck_%d" % i, "status")] = "Preview"
snap.vars[("HyperDeck_%d" % i, "slotId")] = "1"
snap.vars[("HyperDeck_%d" % i, "recordingTime")] = "28:00:00"
@@ -213,6 +214,36 @@ class TestChecks(unittest.TestCase):
"19:21:09.001 Rmv 1 27 local. _apple-midi._udp. Gone Soon\n")
self.assertEqual(sp.parse_dns_sd(out), {"NA Tracks", "Lighting PC"})
def test_vista_heartbeat(self):
self.snap.artnet_since = self.now - 60
self.snap.artnet_last = {"10.1.10.206": self.now - 1}
chk = {"source": "10.1.10.206", "max_silence_seconds": 5, "msg": "VISTA SILENT"}
self.assertEqual(sp.check_artnet(chk, self.snap, self.ctx)[0][1].level, sp.OK)
self.snap.artnet_last = {"10.1.10.206": self.now - 8}
self.assertEqual(sp.check_artnet(chk, self.snap, self.ctx)[0][1].msg, "VISTA SILENT")
self.snap.artnet_since = self.now - 2 # just started listening: no verdict
self.assertEqual(sp.check_artnet(chk, self.snap, self.ctx)[0][1].level, sp.OK)
self.snap.artnet_since = None # could not listen: no verdict
self.assertEqual(sp.check_artnet(chk, self.snap, self.ctx)[0][1].level, sp.OK)
def test_artnet_listener_hears_a_poll(self):
import socket as _s
snap, stop = sp.Snapshot(), threading.Event()
probe = _s.socket(_s.AF_INET, _s.SOCK_DGRAM)
probe.bind(("127.0.0.1", 0))
port = probe.getsockname()[1]
probe.close()
try:
self.assertIsNotNone(sp.start_artnet_listener(snap, stop, port=port))
time.sleep(0.2)
tx = _s.socket(_s.AF_INET, _s.SOCK_DGRAM)
tx.sendto(b"Art-Net\x00\x00\x20\x00\x0e\x00\x00", ("127.0.0.1", port))
tx.sendto(b"not art-net", ("127.0.0.1", port))
time.sleep(0.6)
self.assertIn("127.0.0.1", snap.artnet_last)
finally:
stop.set()
def test_midi_peer_joining_is_not_an_error(self):
for p in self.snap.midi["NA Ingest"]["peers"]:
p["state"] = "connected" # joined, clock sync not finished yet
@@ -470,8 +501,12 @@ class TestFixes(unittest.TestCase):
self.snap.conns["HyperDeck_%d" % i]["category"] = "error"
self.snap.vars[("HyperDeck_3", "status")] = "Record" # last known state: recording
self.assertEqual(self.plan("rec"), [("fix", "hyperdeck"), ("fix", "hyperdeck")])
decks = [chk["conn"] for _, _, _, chk in self.engine.fix_plan("rec", self.snap)]
self.assertEqual(decks, ["HyperDeck_2", "HyperDeck_5"])
decks = [(chk["conn"], chk["ip"]) for _, _, _, chk in self.engine.fix_plan("rec", self.snap)]
self.assertEqual(decks, [("HyperDeck_2", "10.1.10.12"), ("HyperDeck_5", "10.1.10.15")])
# the address comes from Companion and is remembered if the connection loses it
self.snap.vars[("HyperDeck_2", "ip")] = None
decks = [(chk["conn"], chk["ip"]) for _, _, _, chk in self.engine.fix_plan("rec", self.snap)]
self.assertEqual(decks[0], ("HyperDeck_2", "10.1.10.12"))
self.assertEqual(self.plan("hd3"), [])
def test_disabled_connection_is_switched_on_never_rebooted(self):