Wiring: layouts (Hub, Columns, Groups, Free), All/None, Dante in its own box, gentle trackpad zoom; fix the Keys pages (a second wireLayout) and Computers > Setup (a second setupHtml)

RossTalk and OSC: the watchdog reads Companion's RossTalk port (ROSSTALK OFF, PROP ROSSTALK LOST at NA/WS/SC),
Bible TV and Ableton must be listening for Companion's OSC (BIBLE OSC OFF, ABLETON OSC OFF), and both are their own
connection types on the Wiring screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 13:45:09 -04:00
co-authored by Claude Opus 5.5
parent 26804e4ce2
commit 5d0263a9b9
11 changed files with 490 additions and 165 deletions
+28 -2
View File
@@ -526,6 +526,8 @@ class Site:
# "like a wiring diagram ... hide different connections ... how many and what scripts are running on each machine").
WIRE_TYPES = [
{"id": "companion", "label": "Companion control", "color": "#4f8cff", "hint": "Companion's connections: what the deck's buttons drive"},
{"id": "rosstalk", "label": "RossTalk", "color": "#8bc34a", "hint": "RossTalk (port 7788): ProPresenter's cues into Companion, Companion to the Resi decoder"},
{"id": "osc", "label": "OSC", "color": "#f5d142", "hint": "OSC from Companion (Bible TV, Ableton, the DiGiCo relay)"},
{"id": "midi", "label": "Network MIDI", "color": "#b36bff", "hint": "rtpMIDI / Audio MIDI Setup sessions and their peers"},
{"id": "watch", "label": "Watchdog", "color": "#8a94a6", "hint": "What the status panel logs in to or pings"},
{"id": "web", "label": "Web checks", "color": "#2bb3a3", "hint": "Web pages the panel asks (apps' own pages, Resi's cloud)"},
@@ -580,7 +582,17 @@ class Site:
return
key = "|".join([kind] + sorted([a, b]) + [label])
edges[key] = {"id": key, "type": kind, "from": a, "to": b, "label": label, "light": light}
conns, conn_hosts = snap.get("conns") or {}, snap.get("conn_hosts") or {}
conns, conn_hosts, info = snap.get("conns") or {}, snap.get("conn_hosts") or {}, snap.get("conn_info") or {}
rt = snap.get("rosstalk") or {}
def protocol(label):
"""What a Companion connection speaks, when it is one of the two the user follows (2026-10-27)."""
module = (info.get(label) or {}).get("module", "").lower()
if "osc" in module:
return "osc"
if module == "resi-decoders": # its decoders take RossTalk on 7788
return "rosstalk"
return "companion"
gear = cfg.get("gear") or {}
kinds = {"hyperdeck": "recorder", "tascam": "recorder", "shure": "wireless", "psm": "in-ears", "atem": "switcher"}
conn_kind = {c["conn"]: kinds.get(c["type"], "device") for t in cfg["tiles"] for c in t.get("checks", []) if c.get("conn")}
@@ -593,7 +605,21 @@ class Site:
node = target(address, label, conn_kind.get(label, "device")) if address else target(None, label, "service")
if node.startswith("d:"):
nodes[node]["light"] = light if nodes[node]["light"] in ("unknown", "ok") else nodes[node]["light"]
edge("companion", me_id, node, label, light)
kind = protocol(label)
port = (info.get(label) or {}).get("port")
edge(kind, me_id, node, label + (" (OSC to port %s)" % port if kind == "osc" and port else " (RossTalk)" if kind == "rosstalk" else ""), light)
# RossTalk into Companion: who is connected to its listener now, and who must be (a "rosstalk" check).
want = {c.get("address"): c for t in cfg["tiles"] for c in t.get("checks", []) if c["type"] == "rosstalk" and c.get("address")}
for c in rt.get("clients", []):
local = c["ip"].startswith("127.") or owner.get(c["ip"]) == me
src = me_id if local else target(c["ip"], c["ip"])
edge("rosstalk", src, me_id, "RossTalk into Companion%s" % (" from " + c["cmd"] if c.get("cmd") else ""), "ok")
for addr, c in want.items():
here = any((x["cmd"] or "").lower().startswith((c.get("process") or "").lower()[:9]) for x in rt.get("clients", [])) if addr == "local" \
else any(x["ip"] == addr for x in rt.get("clients", []))
if rt and not here:
src = me_id if addr == "local" else target(addr, addr)
edge("rosstalk", src, me_id, "RossTalk into Companion: NOT CONNECTED", "problem")
sessions = {me: snap.get("midi") or {}} if me else {}
sessions.update(snap.get("remote_midi") or {})
for alias, sess in sessions.items():