diff --git a/config.json b/config.json index d3a924e..300dc0e 100644 --- a/config.json +++ b/config.json @@ -935,8 +935,8 @@ "pco_module": "pco-plan", "pco_service_type": "275974", "projects": "~/Library/CloudStorage/GoogleDrive-media@waterschurch.org/Shared drives/Waters Creative/Ableton/Projects", - "prop_bundle_folder": "~/Library/CloudStorage/GoogleDrive-media@waterschurch.org/Shared drives/Location Assets/{date}", - "prop_bundle_host": "ingest", + "prop_bundle_folder": "/Volumes/Location Assets/{date}", + "prop_bundle_host": "prop", "prop_bundle_pattern": "*.probundle", "prop_host": "prop", "prop_lists": [ @@ -2298,5 +2298,6 @@ "command": "sp_cmd", "heartbeat": "sp_hb", "state": "sp_state" - } + }, + "nav_locations_band": true } diff --git a/make_page.py b/make_page.py index 5a2f01b..b50281e 100644 --- a/make_page.py +++ b/make_page.py @@ -265,6 +265,28 @@ def nav_templates(cfg): raise FileNotFoundError("no nav key templates for Companion %s" % version) +REMOTE_VAR = "sp_remote" # North Attleboro's summary of the other locations (settings/campuses.py writes it) +BAND_BLUE, BAND_DARK = 0x1E6FFF, 0x0B2A66 + + +def locations_band(flash_var): + """A blue band across the bottom of NA's page-number key naming the other locations with a problem + ("SC", "SC WS"): it flashes until that location acknowledges, then stays. Red stays NA's own + (2026-10-21, the user: "i dont want the NA page buttons to flash red, that should he reserved for on site + problems").""" + r = "$(custom:%s)" % REMOTE_VAR + on = "$(internal:time_unix) - jsonpath(%s, '$.t') < 30 && jsonpath(%s, '$.n') > 0" % (r, r) + color = "jsonpath(%s, '$.f') == 1 && $(custom:%s) == 1 ? %d : %d" % (r, flash_var, BAND_DARK, BAND_BLUE) + box = {"id": stable_id("nav", "band_box"), "name": "Locations", "usage": "auto", "type": "box", "enabled": prop(on, True), + "opacity": prop(100), "x": prop(0), "y": prop(60), "width": prop(100), "height": prop(40), "rotation": prop(0), + "color": prop(color, True), "borderWidth": prop(0), "borderColor": prop(0), "borderPosition": prop("inside")} + text = {"id": stable_id("nav", "band_text"), "name": "Locations text", "usage": "auto", "type": "text", "enabled": prop(on, True), + "opacity": prop(100), "x": prop(0), "y": prop(60), "width": prop(100), "height": prop(40), "rotation": prop(0), + "text": prop("jsonpath(%s, '$.x')" % r, True), "color": prop(0xFFFFFF), "halign": prop("center"), "valign": prop("center"), + "fontsize": prop("auto"), "fontsizeAllowShrink": prop(True), "font": prop("companion-sans"), "outlineColor": prop(4278190080)} + return [box, text] + + def nav_key(kind, names, status_page=None, hold_ms=1000, tap_page=1, cfg=None): """Companion's own UP / page number / DOWN key, coloured like the ALL button. @@ -291,6 +313,8 @@ def nav_key(kind, names, status_page=None, hold_ms=1000, tap_page=1, cfg=None): layer["borderColor"] = prop(fg, True) paint(layer.get("children", [])) paint(key["style"]["layers"]) + if kind == "pagenum" and (cfg.get("nav_locations_band") or False): + key["style"]["layers"] += locations_band(opts["flash"]) if kind == "pagenum" and status_page: step = key["steps"]["0"] tap = step["action_sets"]["down"] diff --git a/ready-page.companionconfig b/ready-page.companionconfig index 20ab251..fc78fa9 100644 Binary files a/ready-page.companionconfig and b/ready-page.companionconfig differ diff --git a/restart-page.companionconfig b/restart-page.companionconfig index 23018e4..13282a8 100644 Binary files a/restart-page.companionconfig and b/restart-page.companionconfig differ diff --git a/schema.py b/schema.py index 18fbad5..aa22f61 100644 --- a/schema.py +++ b/schema.py @@ -257,6 +257,9 @@ field("tiles[].id", "id", None, "Used inside Companion.", "Keys", advanced=True, field("tiles[].label", "str", None, "The first line on the key.", "Keys", required=True, apply="pages") field("tiles[].pos", "list", None, "[row, column]; absent = no key of its own (shown inside a group).", "Keys", apply="pages") +field("nav_locations_band", "bool", False, "North Attleboro: a blue band on the page-number keys names the other locations " + "with a problem (flashing until acknowledged there). Red stays for this location's own problems.", "Keys", advanced=True, + apply="pages") field("tiles[].kind", "enum", None, "A special key: master (ALL), service (ALARMS), network (NET), ready (READY: " "opens the READY page and sums up its checklist), autofix (AUTO-FIX: its own switch, so ALARMS only " "silences), bypass (hold: hand a device to an operator - its MIDI links out, its Companion connections off).", diff --git a/settings/campuses.py b/settings/campuses.py index a98167d..ed7b4de 100644 --- a/settings/campuses.py +++ b/settings/campuses.py @@ -104,6 +104,7 @@ def http_json(url, body=None, timeout=3): # --- the pages (the hub only) ----------------------------------------------------------- VIEW = {"state": "sp_state_view", "heartbeat": "sp_hb_view"} +REMOTE = make_page.REMOTE_VAR # which other locations have a problem: the blue band on NA's page-number keys SELECT = "sp_view" VIEW_CMD = "sp_view_cmd" # a tap or hold on the LOCATION page, passed on to that location's own watchdog MODE = "sp_view_mode" # "" = that location's status page, "RESTART" = its Restart page @@ -205,7 +206,7 @@ def ensure_variables(cfg, ids): from settings import campus have, _ = campus.companion_state(cfg) want = [n for cid in ids for n in ("sp_state_" + cid, "sp_hb_" + cid) if n not in have] - want += [n for n in (VIEW["state"], VIEW["heartbeat"], SELECT, VIEW_CMD, MODE) if n not in have] + want += [n for n in (VIEW["state"], VIEW["heartbeat"], SELECT, VIEW_CMD, MODE, REMOTE) if n not in have] if not want: return comp = cfg.get("companion") or {} @@ -385,6 +386,8 @@ class Mirror: threads.append(t) for t in threads: t.join(2) + if (data.get("pages") or {}).get("overview"): + self.site.comp.set_custom(REMOTE, json.dumps(remote_summary(others, self.remote, time.time()), separators=(",", ":"))) # The LOCATION page shows the tapped location: its keys moved onto their cells. pick = (self.site.comp.get_custom(SELECT) or "").strip().lower() # held as "WS": the back key shows it if pick not in others and others: @@ -404,6 +407,28 @@ class Mirror: self.site.comp.set_custom(VIEW["heartbeat"], str(st.get("hb") or "0")) +def remote_summary(others, remote, now, stale=30): + """{"t", "n", "x", "f"}: the other locations with something down (their ALL key not "ALL OK", or not + answering: "SC?"), named by id; "f" = 1 while any of them is still flashing (not acknowledged there).""" + names, flashing = [], False + for cid in sorted(others): + st = remote.get(cid) + tag = cid.upper() + if not st or now - float(st.get("hb") or 0) > stale: + names.append(tag + "?") + flashing = True + continue + try: + all_ = json.loads(st.get("state") or "{}").get("all") or {} + except ValueError: + all_ = {} + if not all_ or str(all_.get("x") or "").startswith("ALL OK"): + continue + names.append(tag) + flashing = flashing or all_.get("b") != all_.get("b2") + return {"t": int(now), "n": len(names), "x": " ".join(names), "f": 1 if flashing else 0} + + def campus_command(keys, text, now, restart=False): """The LOCATION page's taps and holds ("tap 1 3