Hold Woonsocket's keys from NA; MIDI links moved and fixed on Macs without python; one check per link

- NA's CAMPUS page (99): tap = acknowledge, hold = fix, at the campus shown. NA's settings page
  turns the cell into that campus's key and writes the command into that campus's Companion
  (sp_cmd), exactly as a press on its own deck does. Logged on both sides.
- coremidi.JXA_CONNECT: connect_peer in JavaScript for Automation, used when a Mac has no python
  (no Command Line Tools): a MIDI hold now reconnects Woonsocket's Tracks, FOH and Lights.
- Woonsocket's MIDI links are on wired addresses now (Tracks to Lighting 10.2.2.2, Tracks to FOH
  10.2.1.12; the other ends list Tracks at 10.2.1.219), and the wired-network rule is back on there.
- Auto-setup keeps one check per MIDI link (the end that reports the link's state): two pulled
  links read 4 DOWN before.

Tried live: a hold sent from NA's page 99 reconnected the FOH link at Woonsocket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 17:00:31 -04:00
co-authored by Claude Opus 5.5
parent 457335bc96
commit b793490d90
5 changed files with 119 additions and 7 deletions
+8 -3
View File
@@ -133,8 +133,8 @@ class TestBuild(unittest.TestCase):
cfg, _ = ac.build(BASE, inv, {"id": "ws", "name": "Woonsocket"}, "1234")
midi = next(t for t in cfg["tiles"] if t["label"] == "MIDI")
got = sorted((c.get("host"), c["peer"], c["address"]) for c in midi["checks"] if c["type"] == "midi_peer")
self.assertEqual(got, [("foh", "WS Tracks", "10.4.1.219:5004"), ("lights", "WS Tracks", "10.4.1.219:5004"),
("tracks", "Lighting", "10.4.2.2:5006"), ("tracks", "WS FOH Mac mini", "10.4.1.12:5004")])
# One check per link: Tracks-Lights from Lights (it reports the state), Tracks-FOH from one end only.
self.assertEqual(got, [("lights", "WS Tracks", "10.4.1.219:5004"), ("tracks", "WS FOH Mac mini", "10.4.1.12:5004")])
self.assertEqual(schema.validate(cfg)[0], [])
import status_panel as sp
snap = sp.Snapshot()
@@ -312,7 +312,12 @@ class TestCampusesView(unittest.TestCase):
self.assertIn("$(custom:sp_view)", json.dumps(ctrls["3"]["0"]["style"])) # it says which campus is shown
cells = [ctl for row in ctrls.values() for ctl in row.values() if "campus view" in (ctl.get("options") or {}).get("notes", "")]
self.assertEqual(len(cells), 28)
self.assertTrue(all(c["steps"]["0"]["action_sets"] == {"down": [], "up": []} for c in cells)) # no press, no hold
acts = cells[0]["steps"]["0"]["action_sets"]
self.assertEqual(sorted(acts), ["2000", "down", "up"]) # tap = acknowledge, hold = fix, there
self.assertIn("sp_view_cmd", json.dumps(acts))
self.assertEqual(cv.campus_command([{"id": "hd1", "pos": [0, 2]}, {"id": "midi", "pos": [1, 3]}],
"tap 0 2 1000;hold 1 3 1000;hold 3 3 1000;hold 1 3 900", 1005),
["ack hd1", "restart midi 1000"]) # an empty cell and a stale hold are dropped
self.assertIn("sp_state_view", json.dumps(cells[0]["style"]))
self.assertTrue(push_page.safe_target(export)[0]) # a rebuild may overwrite it