557 lines
227 KiB
Markdown
557 lines
227 KiB
Markdown
# Status Panel: inventory of everything configurable (2026-10-13)
|
|||
|
|
|
||
|
|
Every setting, hard-coded value, installed piece, Companion-side object, secret and workflow step the system has today: 544 items in four lenses, gathered by four readers (the "what runs where" reader checked NA Ingest live, read-only). Each line: [kind] area :: name @ where | how it is changed today | values/validation | what another campus would change | whether it needs to be editable. Used by the settings-page plan (settings-plan.md) and its coverage table (settings-plan-details.md).
|
||
|
|
|
||
|
|
### Lens: Operator workflow (every step a person does today to change something) and the Companion-side state the panel depends on (what another campus must recreate inside Companion)
|
||
|
|
- [workflow-step] workflow: edit :: Edit config.json in the repo on the MacBook (source of truth) @ /Users/christian/Documents/Status Indicators/config.json (README.md:139) | today: Open config.json in a text editor; every tile/check/fix/host/window change starts here. Nothing on NA Ingest is edited directly. | JSON only; no schema file; typos are caught only by install.sh's json.load or by load_config (unknown check type, unknown member/fix/host, duplicate tile id, restart key with a tile's id, auto_fix fix that pkill/taskkill/killall's without restart_ok). | other campus: Another campus needs its own config.json (and its own repo or branch); today there is one file for NA only.
|
||
|
|
- [workflow-step] workflow: edit :: Validate config.json before deploying (load_config) @ status_panel.py:2234-2276 load_config; .claude/settings.local.json allowlist shows the command | today: /usr/bin/python3 -c "import status_panel as sp; sp.load_config('config.json')" from the repo folder (also runs implicitly in make_page.py and in the tests' CONFIG = sp.load_config(...)). | Raises ValueError on: duplicate tile id; unknown check type (not in CHECKS); member not a tile id; check 'fix' not in fixes (except restart-connection / dante-auto); ssh fix whose host is not in hosts; remote check with unknown host; hold_always not in fixes; auto_fix fix unknown or containing pkill|taskkill|killall without restart_ok; restart key id equal to a tile id; restart key fix or watch entry unknown (watch may be 'conn:<label>'). It does NOT check tile positions overlap (make_page.place does), connection labels exist in Companion, hosts answer, or playlist URIs. | other campus: Same validator for every site; a UI must run it (or an equivalent) before saving.
|
||
|
|
- [workflow-step] workflow: test :: Run the offline tests @ tests/test_status_panel.py (README.md:169) | today: /usr/bin/python3 -m unittest discover -s tests (from the repo folder on the MacBook; ~1771 lines, 9 test classes) | Classes: TestChecks, TestTextSize, TestBehaviour, TestFixes, TestHyperDeckProbe (FakeDeck TCP server on 9993), TestNetgearParsing, TestAgainstFakeCompanion (ThreadingHTTPServer imitating /api/connections, /api/variable, /api/custom-variable, /api/connections/:id/restart), TestPage (make_page.build/build_restart + push_page.safe_target), TestCoreMIDI (real CoreMIDI loopback). Stubs: engine.executor and poe_executor replaced with lambdas (no real fix ever runs); end-to-end test replaces poll_mdns, poll_system, poll_midi, poll_remote, poll_dante_map, start_remote_midi_streams, pops cfg['atem'], sets gateway None; AutoLog dir = tempfile; service_windows pinned to Sunday 07:00-12:30; two remote-MIDI tests run coremidi.py in a local /usr/bin/python3 subprocess. | other campus: Tests read the repo's config.json and hard-code NA facts: page 19/20, name '20\nRestart', RESTART key at [2,6], tiles[0].pos == [0,1], hd1 at row1 col1, ingest at 3/5, net at 3/4, REC at 0/2, 'ack hd1', 'force rs_tascam', ATEM connection label, 'x32' fallback check. A different layout breaks TestPage/TestFixes unless tests become config-driven. | (need not be editable)
|
||
|
|
- [workflow-step] workflow: test :: Poll once on NA Ingest without writing (status_panel.py --once) @ status_panel.py:2445-2476 run_once; :2483 arg; README.md:168 | today: ssh checklist-ingest 'cd ~/Library/Application\ Support/status-panel && /usr/bin/python3 status_panel.py --once' (prints r<row>c<col> tile level text, plus hidden tiles). --dry-run runs the loop but never writes to Companion. | Needs Companion at config.companion (127.0.0.1:8000) so it only works on NA Ingest; no debounce; pings run twice; MIDI errors are printed not raised; it does SSH to the other machines (poll_remote) and reads nothing from the ATEM/Dante map. | other campus: Same on any Ingest Mac.
|
||
|
|
- [workflow-step] workflow: deploy :: Copy the changed files to NA Ingest's staging folder @ README.md:142; .claude/settings.local.json (older 4-file variant) | today: scp status_panel.py coremidi.py netgear.py config.json install.sh checklist-ingest:status-panel-install/ | Staging folder ~/status-panel-install/ on NA Ingest (home of user 'Studio'). README's list omits atem_watch.js and atem-reference.xml although install.sh copies atem_watch.js unconditionally (cp fails under set -e if it is missing from the staging folder) and atem-reference.xml when present. Tests, make_page.py, push_page.py, nav_keys.py are not deployed (they run on the MacBook). | other campus: Each site has its own Ingest host alias and staging folder; the file list must be generated, not remembered.
|
||
|
|
- [external-setup] workflow: deploy :: SSH alias checklist-ingest (how the MacBook reaches NA Ingest) @ ~/.ssh/config:5-10 on the MacBook | today: Host checklist-ingest -> HostName 10.1.1.1, User Studio, IdentityFile ~/.ssh/id_ed25519_checklist_ingest, IdentitiesOnly yes, ConnectTimeout 10. Edited by hand in ~/.ssh/config. | NA Ingest also answers as na-ingest.local and 10.6.3.222 (second network). | other campus: One alias per campus Ingest Mac; the UI (if it runs ON the Ingest Mac) removes the need for this hop. | (need not be editable)
|
||
|
|
- [workflow-step] workflow: deploy :: Run the installer on NA Ingest @ install.sh:1-60; README.md:148 | today: ssh checklist-ingest 'zsh ~/status-panel-install/install.sh' | Steps: set -e; json.load config.json (refuses invalid JSON); mkdir DEST; if DEST/config.json exists and differs -> copy to DEST/config.json.bak-YYYYmmdd-HHMMSS; cp status_panel.py coremidi.py netgear.py config.json atem_watch.js (+ atem-reference.xml if present) to DEST; rewrite the LaunchAgent plist; launchctl bootout; wait up to 10 s for the old job to vanish (bootstrap too early -> error 5); launchctl bootstrap with 3 tries; prints 'installed ... log: ~/Library/Logs/status-panel.log'. No rollback of the Python files (only config is backed up); no 'is a service live right now' guard. | other campus: Same script; DEST/LABEL/log paths are hard-coded org.waterschurch names.
|
||
|
|
- [workflow-step] workflow: deploy :: install.sh --remove (stop the watchdog) @ install.sh:15-20; README.md:170 | today: ssh checklist-ingest 'zsh ~/status-panel-install/install.sh --remove' -> launchctl bootout + rm plist; files in DEST stay. | After removal every page key turns purple WATCHDOG DOWN within 15 s (sp_hb stale). | other campus: Same.
|
||
|
|
- [hardcoded] NA Ingest install :: Install folder (data dir) on NA Ingest @ install.sh:11 DEST="$HOME/Library/Application Support/status-panel" | today: Edit install.sh. Comment: App Support, not ~/Documents, because launchd-run python3 cannot read ~/Documents (TCC). | Holds status_panel.py, coremidi.py, netgear.py, atem_watch.js, config.json, config.json.bak-*, atem-reference.xml, atem-reference.json (generated), dante-map.json, service-mode.json. | other campus: Same path works on any Mac; keep it. | (need not be editable)
|
||
|
|
- [hardcoded] NA Ingest install :: LaunchAgent org.waterschurch.status-panel @ install.sh:9 LABEL; :12 PLIST=~/Library/LaunchAgents/$LABEL.plist; :30-49 plist body | today: Rewritten by install.sh every run: /usr/bin/python3 DEST/status_panel.py --data-dir DEST; RunAtLoad; KeepAlive; ThrottleInterval 10; StandardErrorPath ~/Library/Logs/status-panel.err.log; domain gui/<uid> (must run in the logged-in GUI session: keychain, osascript to Spotify, CoreMIDI). | Restart by hand: launchctl kickstart -k gui/$(id -u)/org.waterschurch.status-panel. --config defaults to <script dir>/config.json; --log defaults to ~/Library/Logs/status-panel.log. | other campus: Label could carry the campus name but does not need to.
|
||
|
|
- [runtime-data] NA Ingest install :: Watchdog log files @ status_panel.py:2485 --log default; :2491 RotatingFileHandler 1 MB x3; install.sh:46 err log; README.md:173 | today: Read with ssh checklist-ingest 'tail ~/Library/Logs/status-panel.log' or grep HOLD|FIX|AUTO. Every fault/clear, ACK, HOLD, FIX, FORCE, AUTO line is timestamped. | ~/Library/Logs/status-panel.log (+ .1 .2 .3), ~/Library/Logs/status-panel.err.log (python tracebacks), ~/Desktop/Auto-Fix Logs/<date> <weekday> Auto-Fix.log (auto_fix.log_dir default, one per day, deleted a calendar month later). | other campus: Same.
|
||
|
|
- [runtime-data] NA Ingest install :: Runtime state files in the data dir @ status_panel.py:2384 service-mode.json; :1840 dante-map.json; :2107 atem-reference.json; install.sh:25 config.json.bak-* | today: Written by the watchdog; never edited. service-mode.json = ALARMS override + last scheduled state; dante-map.json = name->ip->mac->switch/port/shared/poe/seen (every 30 s until first success then 600 s); atem-reference.json = parsed restore XML, rewritten at every start; config.json.bak-<timestamp> = previous config before each differing install. | No pruning of config.json.bak-* files; no history of what changed. | other campus: Same.
|
||
|
|
- [workflow-step] workflow: pages :: Rebuild the two Companion page files (make_page.py) @ make_page.py:296-304 main; README.md:154 | today: python3 make_page.py (on the MacBook, in the repo) -> writes status-page.companionconfig and restart-page.companionconfig (gzipped JSON). Only needed when a tile/key is added, moved, relabelled (stale text), when restart_page/nav settings change, or the expressions change; watchdog-only changes need no rebuild. | python3 make_page.py <path> writes only the status page to <path>. Refuses two buttons on one position (ValueError 'two buttons at row r column c'). Imports load_config so a bad config stops it. Both .companionconfig files are committed to git. | other campus: Same tool; output depends only on config.json.
|
||
|
|
- [workflow-step] workflow: pages :: Import the status page into Companion (push_page.py) @ push_page.py:168-224; README.md:160-163 | today: python3 push_page.py (from the MacBook; default --host na-ingest.local --port 8000, page and expected name from config.page/page_name, file status-page.companionconfig) | Refuses when: the built file's page name != config page_name ('builds page X, not Y'); the target page is not empty-but-nav-keys and not already named the same (use --force to overwrite anyway); Companion rejects the upload ('Companion could not read the file'); another upload session is open (waits up to 40x3 s for it to expire). Needs Companion's admin port reachable on the LAN with no auth. Page name is read before/after via /api/variable/internal/page_number_N_name/value. | other campus: Host must be that campus's Ingest; page numbers come from that site's config.
|
||
|
|
- [workflow-step] workflow: pages :: Import the Restart page (push_page.py --which restart) @ push_page.py:178-181; README.md:94 | today: python3 make_page.py && python3 push_page.py --which restart (page 20, name '20\nRestart', file restart-page.companionconfig) | Same refusals as the status page. Other flags: --page N, --file F, --host, --port, --force. | other campus: Same.
|
||
|
|
- [workflow-step] workflow: pages :: Alternative: import by hand in Companion's UI @ README.md:134,157; memory companion-status-page.md:20 | today: Copy the .companionconfig to NA Ingest's Desktop (use a NEW filename: overwriting in place keeps Finder's old date), then Companion web UI -> Import/Export -> Import -> 'import into page 19' (single page). | Never a full import: a full import resets ALL custom/expression variables and pages (memory :16). Trigger import only with replaceExisting=false. | other campus: Same. | (need not be editable)
|
||
|
|
- [hardcoded] workflow: pages :: push_page's safe-target rule (page emptiness) @ push_page.py:122-159 NAV_TYPES, NAV_MARKER, real_buttons, safe_target | today: Edit push_page.py. A page is safe if its name equals the expected name, or it holds nothing but pageup/pagenum/pagedown controls or buttons whose notes contain 'STATUS nav key'. | Pages 22 and 97 are named 'PAGE' yet hold real buttons, which is why the name alone is not trusted. | other campus: Same rule everywhere. | (need not be editable)
|
||
|
|
- [companion-side] workflow: pages :: tRPC import sequence used by push_page.py @ push_page.py:195-220 (WebSocket /trpc; importExport.prepareImport.start -> uploadChunk (256 KiB, base64) -> complete (sha1, userData null) -> importExport.importSinglePage {targetPage, sourcePage 1, connectionIdRemapping {}}) | today: Internal Companion 5.0.7 API, hand-implemented over a minimal WebSocket client (stdlib only). | Written against Companion 5.0.7; a Companion upgrade can change method names or the export format. | other campus: Each campus's Companion must be a compatible version. | (need not be editable)
|
||
|
|
- [companion-side] workflow: pages :: Page export fetch used by push_page/nav_keys @ push_page.py:126-134 GET /int/export/page/<n>; nav_keys.py:32-43 same with ?includeSecrets=false (HTTPError = no such page) | today: Not changed; internal Companion endpoint returning gzipped page JSON. | nav_keys.py walks page 1, 2, 3... until the first HTTPError, so a gap in page numbers would stop the walk early. | other campus: Same. | (need not be editable)
|
||
|
|
- [workflow-step] workflow: nav keys :: Colour the page-number key on every page (nav_keys.py) @ nav_keys.py:78-122; README.md:96-104; guideline 9 | today: python3 nav_keys.py --dry-run (list), python3 nav_keys.py (apply), python3 nav_keys.py --revert (put Companion's built-in keys back). Re-run after adding or moving pages. | Scans every page except the status page; for each nav key of a kind in config.nav_keys it tRPC controls.copyControl's from the status page's row 1 col 0 (NAV_LOCATIONS) onto that location; kinds no longer listed get controls.resetControl back to the built-in type. Needs the status page already imported (it copies from it). Raises if a copy returns false. Default --host na-ingest.local. | other campus: Page count and nav key positions differ per site; run per campus.
|
||
|
|
- [runtime-data] workflow: nav keys :: nav_locations.json (record of converted nav keys) @ nav_locations.json (97 entries); nav_keys.py:28,89,111,117,121 | today: Written by nav_keys.py after every run (page/row/col -> kind), committed to git. Today: pagenum at 1/0 on pages 1-95 and 97 (96 absent), plus an extra pagenum at 15/0/1. | It is a record only; nav_keys.py re-scans Companion each run rather than trusting it. | other campus: One per campus (lives in the repo today, so a second campus would overwrite it).
|
||
|
|
- [workflow-step] workflow: git :: Commit and push to the private Gitea repo @ git remote origin http://chronicles-ab.waterschurch.org:3000/christian/status-indicators.git; .claude/settings.local.json credential helper line; memory companion-status-page.md:11; guidelines 13,16 | today: git add -A && git commit -m '...' (ends with the Co-Authored-By line) && git push, with credential helper reading the keychain item gitea-mcp (account christian). Commits normally touch README.md, config.json, status_panel.py, tests/, and the two .companionconfig binaries. | Repo must stay private. Branch main only. The two built pages are committed, so a rebuild without a commit leaves the repo stale. | other campus: One repo today; other campuses need their own config (branch, folder, or separate repo) or a sites/ layout. | (need not be editable)
|
||
|
|
- [secret] workflow: git :: Gitea credential in the MacBook keychain @ .claude/settings.local.json (security find-generic-password -s gitea-mcp -a christian -w) | today: Stored once in the login keychain; never printed or typed. | Used only by git push on the MacBook. | other campus: Not needed on the Ingest Macs. | (need not be editable)
|
||
|
|
- [workflow-step] workflow: docs :: Update README.md with every behaviour change @ README.md (216 lines); guideline 16 | today: Hand-edit the relevant table row (Buttons / What each button checks / Restart page / Files) in the same commit. | README is the only teaching material today; it is NA-specific (names, IPs, playlist, page numbers). | other campus: A per-site generated 'what is what' page would replace most of it.
|
||
|
|
- [workflow-step] workflow: docs :: Keep 'the artifact' current @ memory status-panel-guidelines.md:31 ('keep the artifact current'); settings-interface.md mentions docs/ in the repo 'once written' | today: Unknown: no artifact URL or docs/ folder exists in the repo or the memory files I read. | Could not determine what artifact is meant or where it lives. | other campus: n/a | (need not be editable)
|
||
|
|
- [workflow-step] workflow: verify :: Verify live after a change @ memory companion-status-page.md:20; .claude/settings.local.json verification commands | today: Open http://na-ingest.local:8000/tablet?pages=19&cols=8&rows=4 (web buttons, read-only look); ssh checklist-ingest 'grep -E "HOLD|FIX" ~/Library/Logs/status-panel.log | tail'; curl http://127.0.0.1:8000/api/custom-variable/sp_state/value; POST /api/location/19/3/0/press to toggle ALARMS; curl /api/variable/audinate-dantecontroller/devices/value. | Guideline 15: test it yourself before saying done; when the user tested, read the log. | other campus: Host and page number differ.
|
||
|
|
- [workflow-step] workflow: pages :: Replace the ATEM restore file @ README.md:114; install.sh:28; status_panel.py:2109-2115 (parsed into atem-reference.json at start) | today: Save a new restore .xml from ATEM Software Control (today a copy of '4k plus 2026-10-07 14-59-55.xml' from Google Drive Backup/NA/ATEM), copy it over atem-reference.xml in the repo, scp it to the staging folder, re-run install.sh (watchdog restart re-parses it). | config.atem.reference is a path relative to the script dir or absolute; 1.6 MB XML committed to git. | other campus: Every campus has its own switcher and restore file.
|
||
|
|
- [workflow-step] workflow: Companion modules :: Build and install the quiet Tascam module @ tascam-quiet/make_quiet_tascam.py; README.md:187-194 | today: python3 make_quiet_tascam.py '~/Library/Application Support/companion/modules/tascam-da-6400-1.3.0' <out> -> tascam-da-6400-1.3.1-quiet.tgz; then Companion -> Modules -> Import module package; Connections -> tascam -> edit -> version 1.3.1-quiet -> save. | Patches the stock 1.3.0 minified source by string replacement; a newer stock module may not match the PATCHES. | other campus: Only where a DA-6400 exists. | (need not be editable)
|
||
|
|
- [companion-side] workflow: one-time :: Create the three custom variables in Companion by hand @ README.md:130-133; memory companion-status-page.md:16; config.variables; status_panel.py:2414-2425 warnings | today: Companion web UI -> Variables -> Custom Variables -> add sp_state, sp_hb, sp_cmd (start value empty, persist off). Done once on NA. | Cannot be created through the HTTP API (POST to a missing one -> 404); the watchdog logs 'cannot set custom:<name> (HTTP 404) - create it in Companion' once. Names are config.variables.state/heartbeat/command and must match the names baked into the page expressions by make_page.py. Whether tRPC can create them was not determined. | other campus: Must be repeated on every campus's Companion (first thing on the checklist).
|
||
|
|
- [companion-side] companion-side :: Custom variable sp_state (tile JSON) @ config.variables.state; status_panel.py:2410 set_custom; make_page.py:51-66 jsonpath reads | today: Written by the watchdog twice a second when changed (and every 10 s anyway), as compact JSON {tile: {x text, b/f on-phase colours, b2/f2 off-phase colours, s font size}} including hidden tiles and 'all'; sent in the POST body (several KB). | Page expressions: jsonpath($(custom:sp_state), '$.<tile>.x') etc. Tile ids therefore must be valid jsonpath names (letters/digits/underscore). | other campus: Same mechanism. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Custom variable sp_hb (heartbeat) and the 15 s stale rule @ config.variables.heartbeat; make_page.py:34 STALE_SECONDS=15, :53 '$(internal:time_unix) - $(custom:sp_hb) > 15' | today: Watchdog writes unix seconds every 0.5 s loop; every key turns PURPLE 'WATCHDOG DOWN <n> ERR' (master) or '<LABEL>\n?' when older than 15 s. | STALE_SECONDS is a constant in make_page.py (needs page rebuild + re-import to change); PURPLE 0x6A1B9A constant. | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Custom variable sp_cmd (button command queue) and its grammar @ config.variables.command; make_page.py:83-97 command_action; status_panel.py:2341-2375 handle_commands, HOLD_MAX_AGE=15 | today: Buttons append '$(custom:sp_cmd);<cmd>' as plain text (not an expression: '+' is numeric in Companion 5). Watchdog reads, clears, then handles: 'ack <tile>', 'ackall', 'service toggle|on|off', 'restart <tile> <unix>', 'force <key> <unix>'. Holds older than 15 s or unstamped forces are dropped. | Verbs are hard-coded in both make_page.py and status_panel.py. | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Custom variable flash_tick + trigger flash_tick_500 (the blink clock) @ README.md:135; make_page.py:9,61-62,211-212 '$(custom:flash_tick) == 1'; tests FakeCompanion store has flash_tick | today: Pre-existing on NA (not created by this project): a trigger toggling custom variable flash_tick between 0 and 1 every 500 ms; it must stay enabled or nothing blinks. | Hard-coded name 'flash_tick' in make_page.py (not in config.variables). | other campus: Another campus must create both the variable and the trigger by hand (or import a trigger with replaceExisting=false); the name should become a config key.
|
||
|
|
- [config-key] companion-side :: Status page number and name (page 19, '19\nStatus') @ config.page=19, config.page_name='19\nStatus'; make_page.py:255-266 page_export; push_page.py:182,188 | today: Edit config.json, rebuild, push; the page was also renamed once in the admin UI (memory :20). push_page refuses unless the live page already has this exact name or holds only nav keys. | int page; string name with literal backslash-n; page must exist in Companion (Companion 5 pages are created in the UI). | other campus: Every campus picks its own free page numbers; nav hold jumps to this page.
|
||
|
|
- [config-key] companion-side :: Restart page number and name (page 20, '20\nRestart') + jump/back positions @ config.restart_page.page=20, page_name, jump_pos [2,6] (on the status page), back_pos [2,6] (on the restart page); make_page.py:274-288 | today: Edit config.json; rebuild both pages; push both. The RESTART PAGE key (0x37474F) on page 19 and the STATUS PAGE key on page 20 are plain set_page buttons. | Positions are [row, col]; place() refuses overlaps. | other campus: Per site.
|
||
|
|
- [hardcoded] companion-side :: Nav key positions (UP 0/0, page number 1/0, DOWN 2/0) and the ALARMS key at 3/0 @ make_page.py:195 NAV_LOCATIONS (hard-coded); config tiles 'service' pos [3,0] | today: Edit make_page.py. Column 0 is Companion's own nav column on an 8x4 XL; tiles may not be placed on 0/0, 1/0, 2/0. | nav_controls() puts {'type': 'pageup'/'pagenum'/'pagedown'} or the coloured copy at these spots on both pages. | other campus: Same on any Stream Deck XL layout. | (need not be editable)
|
||
|
|
- [config-key] companion-side :: Which nav keys follow ALL, tap page, hold time @ config.nav_keys=['pagenum'], nav_tap_page=1, nav_hold_ms=1000; make_page.py:199-245; README.md:98-104 | today: Edit config.json; rebuild; push page 19; re-run nav_keys.py. Tap (on release) -> set_page nav_tap_page; hold nav_hold_ms -> set_page config.page. | nav_keys subset of pageup/pagenum/pagedown; tap page must be named outright (the converted key's 'startup' means the current page on surfaces set to 'use last page'). | other campus: Per site (home page number differs).
|
||
|
|
- [hardcoded] companion-side :: nav_templates.json (Companion 5.0.7's converted nav keys) @ nav_templates.json (_comment; keys pageup/pagenum/pagedown, button-layered with inc_page/set_page startup/dec_page actions); make_page.py:207 | today: Captured once from page 19 after 'convert to regular button' in Companion 5.0.7; make_page.py recolours box/text/line layers with expressions and rewrites the pagenum steps. | Version-specific layer structure; a new Companion major may need a recapture. | other campus: Same file as long as Companion versions match. | (need not be editable)
|
||
|
|
- [hardcoded] companion-side :: Export format pin: EXPORT_VERSION 12, COMPANION_BUILD '5.0.7+9763-stable-cec2f88e6f', GRID 0-8 x 0-5 @ make_page.py:31-33 | today: Edit make_page.py when Companion changes its export format. | push_page/tRPC calls and nav_templates are also 5.0.7-specific. | other campus: Every campus must run a compatible Companion 5.0.x; record each site's version. | (need not be editable)
|
||
|
|
- [hardcoded] companion-side :: Hold time 2000 ms (HOLD_MS) and runWhileHeld @ make_page.py:36 HOLD_MS; :144-146, :181-182 | today: Edit make_page.py, rebuild, push both pages. Every status tile with a fix, every group, NET, hold_always tiles and every restart key use a 2000 ms action set. | Guideline 3: holding any key 2 s always fixes. | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Button expressions and internal variables the pages rely on @ make_page.py:51-66 (jsonpath(), $(internal:time_unix), $(custom:flash_tick)); :157 $(internal:instance_errors); template string for stale text | today: Baked by make_page.py. Gotchas (memory :18): '+' is numeric; join text with template strings; single-quoted strings process escapes, template strings do not. | Layers: canvas (border decoration), box (bg expression), image (empty), text (companion-sans, fontsize expression from sp_state.s, fontsizeAllowShrink). canModifyStyleInApis true on tiles. | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Button actions used (internal module) @ make_page.py:83-103: custom_variable_set_value (connectionId internal) and set_page (surfaceId self) | today: Baked by make_page.py; ids via stable_id(sha256) so re-imports keep the same ids. | Only the internal connection is referenced; no module connections are in the export ('instances': {}). | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Button notes as machine markers @ make_page.py:140,188,196,233 ('STATUS tile', 'RESTART key', NAV_MARKER 'STATUS nav key (<kind>)'); push_page.py:123,145; nav_keys.py:46-58 | today: Written into each button's notes field; push_page and nav_keys identify our keys by these strings. | Editing a note in Companion's UI would make a key invisible to the scripts. | other campus: Same. | (need not be editable)
|
||
|
|
- [config-key] companion-side :: Companion host/port the watchdog talks to @ config.companion {host 127.0.0.1, port 8000}; status_panel.py:2290 make_companion; optional config.companion.db | today: Edit config.json. HTTP API, no auth, persistent http.client connection, 3 s timeout, one connection object per poller (4). | push_page.py/nav_keys.py do NOT read this; they default to na-ingest.local:8000 (flags --host/--port). | other campus: Same on any Ingest Mac running Companion locally; the LAN name differs.
|
||
|
|
- [companion-side] companion-side :: Companion HTTP endpoints the watchdog uses @ status_panel.py:102-138: GET /api/connections; GET /api/variable/<label>/<name>/value; GET+POST /api/custom-variable/<name>/value (POST body text/plain; '?value=' to clear); POST /api/connections/<id>/restart|disable|enable | today: Not configurable; Companion 5.0.7 HTTP API. Connection ids are resolved from labels at call time. | A 400 is returned for an empty POST body; a 404 for a missing custom variable. | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Connection status fields read for every 'conn'-type check @ status_panel.py:1428-1436 poll_connections every 1 s: label -> {id, enabled, status.category, status.message} | today: Category good/warning/error; enabled false -> grey 'DISABLED' (amber) and a hold turns it back on; 'ignore_warning': true on a check ignores category warning (ProPresenter). | Labels are the only key: renaming a connection in Companion silently breaks its check (shows OFFLINE/unknown). | other campus: Each campus must use the same labels as its config.
|
||
|
|
- [companion-side] companion-side :: Connection addresses from Companion's settings database @ status_panel.py:1552-1593 companion_db_path (newest ~/Library/Application Support/companion/vN.N/db.sqlite, or config.companion.db), companion_conn_hosts (SELECT value FROM instances; JSON label + config.host), poll_conn_hosts every 60 s | today: Opened read-only (mode=ro, 2 s timeout) only when some ping check has a 'conn'; result overrides the check's 'host' fallback (Shure receivers, Tascam). Schema errors are logged and ignored. | Companion's private schema; a Companion upgrade that renames the table or folder breaks the lookup (falls back to config hosts). | other campus: Same path on any Mac; versions folder name differs. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Module variables polled every 1 s (fast list) @ status_panel.py:552-573 needed_variables; :1438 poll_variables; Periodic 'variables' 1.0 s | today: Derived from config: hyperdeck -> status, slotId, recordingTime; dante -> devices; tascam -> error, caution. Each is one GET /api/variable/<label>/<name>/value. | Today: 6 decks x3 + devices + error + caution = 21 GETs/s on one connection. | other campus: Same derivation. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Module variables polled every 3 s (slow list) @ status_panel.py:560-571; Periodic 'slow-variables' 3.0 s | today: hyperdeck -> ip; shure -> ch_N_name, ch_N_battery_bars, ch_N_interference_status for N in 1..channels; psm -> ch_N_name, ch_N_rf_mute. | channels per check (Axient 4, ULXD 1, PSM 2). Variable names are the Shure/PSM module's and are hard-coded in needed_variables and the checks (:325-365). | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side: connections :: HyperDeck_1 .. HyperDeck_6 (Blackmagic HyperDeck module) @ config tiles hd1..hd6 {type hyperdeck, conn HyperDeck_N, optional on 2 and 4, fix {conn: hyperdeck}}, hold_always 'hyperdeck'; status_panel.py:255-290, :987 ip fallback | today: Reads variables status ('record'), slotId, recordingTime (h:m:s), ip; NO DISK / LOW <30 min / FULL <5 min / NOT REC when another deck records. Hold: disable+enable the connection, verify after 15 s; probes port 9993 (hyperdeck_probe) but never reboots. | 'optional': true on a deck = grey with no alarm when it has no disk. Which decks exist is simply which hd tiles are in config and which connections exist in Companion. | other campus: A campus with decks 2 and 4 only: remove/skip the other hd tiles (and REC members) and ensure the labels match its Companion.
|
||
|
|
- [companion-side] companion-side: connections :: tascam (Tascam DA-6400 module, version 1.3.1-quiet) @ config tile tascam {type tascam conn tascam fix tascam_reconnect; ping conn tascam host 10.1.11.74}; status_panel.py:375-384 error/caution; fixes.tascam_reconnect kind reconnect verify 20 s | today: Variables error and caution (text); ping address taken from Companion's connection config (DB) else 10.1.11.74. Hold always reconnects; 'HUNG - POWER CYCLE IT' when it pings but the control port is dead. | Needs the quiet module to keep Companion's log sane. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: audinate-dantecontroller (Dante module) and its 'devices' variable @ config tile dante {type dante conn audinate-dantecontroller, devices map of 19 Dante names -> short labels, fix map by device name + '*': dante-auto}; status_panel.py:297-320, :1880 | today: Variable devices = JSON array of device names present. Config lists the 19 expected names (FOH-DiGiCo-DMI-1/2, BOH-WING, BOH-DQ-Rack, BOH-AD4Q-A/B, STUDIO-A-X32, STUDIO-A-Resi-AJA-SDI, STUDIO-A-Ingest, NA-Translation, STUDIO-B-RedNet-TNX, STUDIO-B-TB, STUDIO-B-TB-MON, STUDIO-B-MON, STUDIO-B-SOLO-MON, STUDIO-B-Tascam, NA-Tracks, FOH-SuperRack-LiveBox, NA-ProPresenter-Mac). Per-device fixes dvs_prop/dvs_tracks/dvs_translation/dvs_ingest; everything else -> PoE cycle via the live Dante map or restart the Dante module. | Device names are Dante names (renaming in Dante Controller needs a config edit; re-patching does not). | other campus: Entire list is per site.
|
||
|
|
- [companion-side] companion-side: connections :: Axient_1, Axient_2 (Shure AD4Q, 4 channels), ULXD-4 (1 channel) @ config hidden tiles axient1/axient2/ulxd {type shure conn ..., channels; ping conn ... host 10.1.1.101/.102/.106}; status_panel.py:325-360 | today: Variables ch_N_name, ch_N_battery_bars (<=1 red, <=2 amber; thresholds battery_err_bars/battery_warn_bars per check), ch_N_interference_status (only while the transmitter is on). Receivers pinged every 3 s at Companion's address for them. Members of the RF group only (no own key). | channels int; ping host fallback. | other campus: Per site RF inventory.
|
||
|
|
- [companion-side] companion-side: connections :: PSM_1 .. PSM_3 (Shure PSM1000, 2 channels) @ config hidden tiles psm1..3 {type psm conn PSM_N channels 2; ping host 10.1.1.103-.105}; status_panel.py:363 | today: Variables ch_N_name, ch_N_rf_mute ('MUTED' = alarm). | Same ping-from-Companion-address rule. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: x32 (Behringer X32) @ config tile x32 {type conn conn x32} | today: Connection status only; hold = restart-connection. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: lighting-midi (Companion's MIDI connection to the lighting port) @ config tile midi check {type conn conn lighting-midi tag 'COMPANION MIDI'} | today: Connection status only, as one line of the MIDI key. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: Propresenter-API (ProPresenter module) @ config tile apps {type conn conn Propresenter-API tag PROPRES fix propresenter ignore_warning true} | today: Status only; its periodic yellow warning is ignored; hold restarts ProPresenter on the ProP Mac over SSH then the connection. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: ableton (OSC), BibleTV (OSC) @ config tile apps checks {conn ableton tag ABLETON}, {conn BibleTV tag 'BIBLE OSC'}; restart key rs_ableton watch ['ableton','conn:ableton'] | today: Status only; ableton_restart fix has conn ableton + reconnect so Companion reconnects after the app restarts. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: ATEM (bmd-atem module) and its bundled atem-connection library @ config tile atem {conn ATEM}; config.atem {host 10.1.10.2, node glob '/Applications/Companion [0-9]*.app/.../node22/bin/node', library glob '~/Library/Application Support/companion/modules/bmd-atem-*/node_modules/atem-connection', reference atem-reference.xml}; status_panel.py:2089-2115 newest() | today: Connection status from Companion; audio/camera compared by atem_watch.js run with Companion's own node and the ATEM module's atem-connection library (highest version number chosen by glob). If either glob finds nothing: 'ATEM checks off' warning and the atem checks never report. | Depends on the Companion app name/location and the module being installed; a Companion update that moves node or the module breaks the watcher silently (warning only). | other campus: Per site switcher IP + restore file; globs may need per-site paths.
|
||
|
|
- [companion-side] companion-side: connections :: OBS-Youtube (OBS module) @ config tile obs {type conn conn OBS-Youtube service_only true fix obs}; hosts.livestream has mac + wake_broadcast | today: Status only; service_only = idle (grey) outside the service window instead of red. Hold starts OBS over SSH (Wake-on-LAN if the PC is off) then reconnects. | service_only is the one exception to 'every key flashes red any day' and service_windows are now 24/7, so it is moot today. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: RESI_Decoder (RossTalk) and resi-studio-cues @ config tile resi checks {conn RESI_Decoder tag DECODER}, {conn resi-studio-cues}; plus pings 10.1.10.203/.202, http://10.1.10.202/, https://central.resi.io/ | today: Status only. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: VX1000 and UHDJr (NovaStar modules) @ config tile led checks {conn VX1000}, {conn UHDJr}, pings 10.1.14.116/.115 | today: Status + ping, because the NovaStar module keeps saying Connected after power-off. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side: connections :: arena (Resolume Arena module) @ config tile arena {type conn conn arena fix arena}; fixes.arena reconnect true | today: Status only; hold starts Arena on the Lighting PC via its StatusPanel task then reconnects. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side :: Fix kinds that act on Companion itself @ status_panel.py:542 RESTARTABLE ('conn','hyperdeck','shure','psm','tascam'); :545 'restart-connection'; :1957 kind reconnect; :1983 kind hyperdeck (disable+enable); execute_fix 'reconnect': true -> restart_connection after a successful app start; disabled connection -> enable only | today: Built in; which applies is derived from the check type and the fix entry. | 60 s cooldown per fix (run_fixes cooldown=60). | other campus: Same. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Stream Deck surfaces and the layout grid @ README.md:10-17 (XL 8x4; MK.2 and Mini show the top-left corner); make_page.py:33 GRID; tests:1657 master at [0,1] 'where the smallest Stream Deck can see it' | today: Surfaces are configured in Companion's Surfaces tab (not by this project); tiles use rows 0-3, cols 0-7; col 0 = UP/page/DOWN + ALARMS. | Surface setting 'use last page' affects the converted page-number key (hence tap page named outright). | other campus: A campus with only an MK.2 (5x3) would need the important keys in the top-left 5x3; layout is per site.
|
||
|
|
- [companion-side] companion-side :: Web buttons / tablet URL for a screen-only view @ memory companion-status-page.md:20: http://na-ingest.local:8000/tablet?pages=19&cols=8&rows=4 | today: Open in a browser on the LAN; read-only look at the page (presses also work there). | Page number and host per site. | other campus: Per site.
|
||
|
|
- [companion-side] companion-side :: Pressing a key over the API (for tests) @ memory :20: POST http://na-ingest.local:8000/api/location/19/3/0/press (ALARMS) | today: curl -X POST ...; same for any row/col. | other campus: Per site. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Why only single-page import is used @ memory companion-status-page.md:16 | today: A full Companion import resets ALL custom/expression variables and pages; only importSinglePage into page 19/20 and trigger import with replaceExisting=false are safe. | other campus: Same caution everywhere. | (need not be editable)
|
||
|
|
- [companion-side] companion-side :: Companion pages 22 and 97 named 'PAGE' with real buttons @ push_page.py:10; tests:1683 | today: Observed NA fact that shaped the safety rule; nothing to change. | other campus: n/a | (need not be editable)
|
||
|
|
- [config-key] config: watchdog :: service_windows (when alarms are armed) and the ALARMS key @ config.service_windows [{days all, 00:00-23:59}]; status_panel.py:696 ServiceMode; tile 'service' kind service pos [3,0] | today: Edit config.json + install. Press ALARMS to override until the next window edge (persisted in service-mode.json). | days from mon..sun; start/end 'HH:MM' with start <= hm < end. | other campus: Per site, but guideline 1 says alarms should be 24/7 everywhere.
|
||
|
|
- [config-key] config: watchdog :: auto_fix window and list @ config.auto_fix {windows [{sun 06:30-13:30}], after_seconds 20, max_tries 2, retry_seconds 90, pause_after_network_seconds 60, restart_connections true, fixes [16 gentle fix ids], log_dir default ~/Desktop/Auto-Fix Logs} | today: Edit config.json + install; load_config refuses a fix that kills a program unless restart_ok. | Today's list: hyperdeck, tascam_reconnect, midi_reconnect, rtpmidi_start, vista, arena, obs, ableton, translate, dvs_prop, dvs_tracks, dvs_translation, solo_afl, atem_audio, atem_camera (+1 truncated in my dump). | other campus: Per site service times.
|
||
|
|
- [hardcoded] config: watchdog :: Poller periods (not configurable) @ status_panel.py:2299-2330 start_pollers: connections 1 s, variables 1 s, slow-variables 3 s, conn-hosts 60 s, spotify 3 s, pings 3 s, midi 0.5 s, system 10 s, bonjour 15 s, http 5 s, remote 10 s, dante-map 30 s (600 s after first success); remote MIDI streams continuous; ATEM watcher; Art-Net listener | today: Edit status_panel.py. | debounce_seconds=3 and flap {count 3, window 600} are config keys; network burst thresholds are config.network. | other campus: Same. | (need not be editable)
|
||
|
|
- [config-key] config: watchdog :: SSH identity and options for every other machine @ config.ssh_key '~/.ssh/id_status_panel'; status_panel.py:1748-1753 ssh_cmd (BatchMode, ConnectTimeout 5, IdentitiesOnly, LogLevel ERROR, StrictHostKeyChecking accept-new, ControlMaster auto, ControlPath /tmp/status-panel-ssh-%C, ControlPersist 120) | today: Key made once on NA Ingest; public key literal is pasted inside remote-access/mac-authorize.sh and windows-setup.ps1 ('ssh-ed25519 AAAAC3...bgY status-panel@NA-Ingest'). | Exit 255 = unreachable -> '<SHORT> NOT REACHABLE' or Wake-on-LAN if the host has 'mac'. | other campus: Each Ingest Mac needs its own key pair and its own copies of the setup scripts with that public key embedded.
|
||
|
|
- [config-key] config: hosts :: hosts table (who the watchdog can SSH to) @ config.hosts: prop napropresenter@10.1.14.225; tracks waterschurchmedia@10.1.3.227; translation studio@10.1.7.39; bibletv media@10.6.7.13; lighting media@10.1.10.206; studiob studiob@10.1.13.175; livestream media@10.1.9.126 + mac 6c:24:08:d7:fb:57 + wake_broadcast 10.1.255.255 | today: Edit config.json + install. Referenced by fixes (host) and remote/midi_peer checks (host). | keys: ssh 'user@ip' (required), mac (Wake-on-LAN), wake_broadcast. | other campus: Entirely per site; this is the 'which computers' list the user wants visible.
|
||
|
|
- [external-setup] external-setup: Macs :: Authorize NA Ingest's key on each Mac (mac-authorize.sh via ARD as root) @ remote-access/mac-authorize.sh; memory :25-26 | today: Apple Remote Desktop -> select Macs -> Send UNIX Command as root -> paste the script. Appends the public key to the console user's ~/.ssh/authorized_keys and prints 'OK user=... mac=... ssh-group=...'. Remote Login must be on (System Settings > Sharing). | Done 2026-10-08 on ProP Mac, Tracks Mac, NA Translation; Studio B Mac Studio later. The user runs it; never passwords. | other campus: Repeat per Mac per campus with that campus's key.
|
||
|
|
- [external-setup] external-setup: Macs :: DVS start helper on each Dante Mac (mac-dvs-helper.sh via ARD as root) @ remote-access/mac-dvs-helper.sh -> /usr/local/sbin/status-panel-dvs-start (defaults write wantToRun 1; launchctl kickstart system/com.audinate.dante.DanteVirtualSoundcard) + /etc/sudoers.d/status-panel (NOPASSWD for that one script); fixes dvs_* run 'sudo -n /usr/local/sbin/status-panel-dvs-start && open -g -a Dante Virtual Soundcard' | today: ARD Send UNIX Command as root on ProP, Tracks, Translation and NA Ingest. Undo: rm both files. | Installed 2026-10-08 on all four Macs. | other campus: Per Mac that runs DVS.
|
||
|
|
- [external-setup] external-setup: Macs :: Studio B Pro Tools solo-mode helper @ remote-access/install-solo-mode.sh + solo-mode-agent.swift -> ~/Library/Application Support/status-panel/solo-mode-agent, LaunchAgent org.waterschurch.status-panel.solo-mode, writes solo-mode.json every second, acts on solo-mode.fix; config apps checks 'PT SOLO NOT AFL' / 'PT SOLO CHECK OFF' (file older than 20 s or trusted false); fix solo_afl | today: From NA Ingest: scp the two files to studiob@10.1.13.175:/tmp/ ; ssh ... 'zsh /tmp/install-solo-mode.sh' (needs swiftc on that Mac); then allow solo-mode-agent in System Settings > Privacy & Security > Accessibility and restart the helper. | Only Mac with a compiled helper; only campus-specific thing on Studio B. | other campus: Only where Pro Tools runs.
|
||
|
|
- [external-setup] external-setup: Windows :: windows-setup.ps1 on each Windows PC (OBS/LiveStream, Lighting, Bible TV) @ remote-access/windows-setup.ps1 (sshd install/auto-start + sc failure restart; firewall rule OpenSSH-Server-In-TCP, Profile Any, RemoteAddress 10.1.1.1 and 10.6.3.222 only; key into C:\ProgramData\ssh\administrators_authorized_keys and %USERPROFILE%\.ssh\authorized_keys; scheduled tasks \StatusPanel\Start OBS|Vista|Arena|rtpMIDI|BibleApp (BibleApp also at logon +15 s; RUNASADMIN apps get RunLevel Highest); rtpMIDIService failure restart; Wake-on-LAN on the NIC) | today: On the PC: PowerShell as administrator, Set-ExecutionPolicy RemoteSigned -Scope CurrentUser, run the script, paste the RESULT block back; restart and rerun if it says so. Needs the user's OK (guideline 12). | $IngestIPs and the public key are hard-coded in the script; app paths are discovered (OBS on D:, Vista on G:/E:). | other campus: Per PC per campus; edit $IngestIPs and $Key for that campus.
|
||
|
|
- [external-setup] external-setup: Windows :: Lighting PC must stay on a Public network profile @ README.md:53; fixes.rtpmidi_start note | today: Manual Windows setting; its Bonjour firewall rules only allow Public; on Private it vanishes from the MIDI directory. | Nothing checks this automatically. | other campus: Same rule for any rtpMIDI PC. | (need not be editable)
|
||
|
|
- [external-setup] external-setup: Windows :: Vista autoload preference and show folder @ README.md:119: <autoloadpath> in E:\media\Documents\Vista 3\.preferences -> Prop Takeover in E:\media\Documents\Vista 3\Shows (set 2026-10-08) | today: Set by hand on the Lighting PC. | other campus: Per site. | (need not be editable)
|
||
|
|
- [secret] external-setup: NA Ingest :: Netgear switch login in the login keychain @ netgear.py:4-8,22-35 (service 'netgear-status-panel', account = username, read with security find-generic-password); config.dante_switches ['10.66.1.100','10.66.1.102']; memory :33 | today: Once, in a GUI session on NA Ingest: security add-generic-password -s netgear-status-panel -a admin -w (prompts). Readable only from the GUI session (hence the watchdog runs as a gui/ LaunchAgent, not over SSH). | Missing/locked -> RuntimeError logged; Dante map and PoE cycling stop working. Never printed. | other campus: Per site switches and credentials.
|
||
|
|
- [external-setup] external-setup: NA Ingest :: Spotify Automation (AppleEvents) permission for the watchdog @ status_panel.py:1636 osascript 'tell application Spotify'; fixes.spotify_play; README.md:123 | today: macOS TCC prompt once for python3/osascript controlling Spotify in the GUI session; how it was granted on NA Ingest is not recorded. | If denied, poll_spotify returns state None with an error string (SPOTIFY key shows the error). The playlist list is fetched from open.spotify.com embed pages + spclient (anonymous token) hourly. | other campus: Per Ingest Mac; playlist URI per site.
|
||
|
|
- [external-setup] external-setup: NA Ingest :: Network MIDI sessions on NA Ingest ('NA Ingest', optional 'NA Ingest Listen') @ config midi checks session 'NA Ingest' peers 'Lighting PC' and 'SuperRack-LiveBox'; midi_rx source 'Network NA Ingest Listen'; README.md:175-185; coremidi.py sessions()/connect_peer() | today: Audio MIDI Setup -> MIDI Studio -> Network: sessions and peers are created by hand once; the watchdog only reads them (ctypes CoreMIDI) and re-adds a dropped peer at its last address or the check's 'address'. | Session and peer names must match exactly; Bonjour instance names ('Lighting PC', 'NA Tracks') for mdns checks likewise. | other campus: Per site session/peer names and addresses.
|
||
|
|
- [external-setup] external-setup: other Macs :: Remote MIDI sessions read over SSH ('NA Tracks' on the Tracks Mac, 'NA ProP' on the ProP Mac) @ config midi_peer checks with host tracks/prop; status_panel.py:1668-1746 (coremidi.py sent over stdin to /usr/bin/python3 on that Mac; one long-lived ssh stream per host) | today: Nothing installed on those Macs; needs only SSH + /usr/bin/python3. Sessions themselves are set up by hand in their Audio MIDI Setup. | Stream shows a drop within ~1-2 s; no verdict while the stream is down. | other campus: Per site.
|
||
|
|
- [external-setup] external-setup: NA Ingest :: Services the INGEST key watches (must exist as LaunchAgents/apps on the Ingest Mac) @ config ingest checks: launchd org.waterschurch.resi-propresenter (BRIDGE), org.waterschurch.lobby-captions (CAPTIONS), org.waterschurch.lobby-captions-display (CAPTION SCREEN); http 127.0.0.1:24480/api/v1/ping (ProdCom); process /Applications/ProdDash.app/... + http 127.0.0.1:24500/ (ProdDash); disk / warn 25 GB err 8 GB; fixes bridge/captions/caption_screen/prodcom/proddash/dvs_ingest kind local | today: Those agents/apps are installed separately (not by this repo); Church Translate's startup item on NA Ingest was moved to ~/Library/LaunchAgents.disabled/ (memory :25). | other campus: Per site set of local services.
|
||
|
|
- [external-setup] external-setup: NA Ingest :: ATEM Software Control on NA Ingest (midiEnabled pref) @ config atem check {type pref domain 'com.blackmagic-design.ATEM Software Control' key midiEnabled want '0'}; fix atem_midi kind local restart_ok (quits/reopens the app) | today: App installed by hand; the watchdog reads 'defaults read' every 10 s. | other campus: Per site.
|
||
|
|
- [config-key] config: tiles :: Hidden tiles (RF members with no key) @ config tiles axient1, axient2, ulxd, psm1, psm2, psm3 have no 'pos'; make_page skips them; run_once prints them as 'hidden' | today: Edit config.json; they show only through the RF group key. | Any tile without pos is allowed; must still be a member somewhere to be visible. | other campus: Per site.
|
||
|
|
- [config-key] config: tiles :: Group keys and their members @ config tiles rec/audio/rf/show/video/stream with 'members' lists | today: Edit config.json, rebuild, push (members changes alone need only install; position/label changes need a page rebuild). | Members must be tile ids; a group shows the first problem + '+N'; hold fixes all members. | other campus: Per site.
|
||
|
|
- [config-key] config: tiles :: Restart page keys @ config.restart_page.keys: 13 keys {id rs_*, label, pos, fix, optional watch [fix ids or 'conn:<label>']} | today: Edit config.json, python3 make_page.py, python3 push_page.py --which restart, install (watchdog reads the keys for FORCE and the flashing 'watch'). | id must not collide with tile ids; fix must exist; watch entries must be fix ids or conn:<label>. | other campus: Per site.
|
||
|
|
- [config-key] config: fixes :: Fix catalogue (26 entries) and their kinds @ config.fixes; status_panel.py:1921-1990 execute_fix; tests:1355 valid kinds ssh/local/hyperdeck/midi_connect/reconnect/atem (netgear_poe exists in code but is not in the test's list) | today: Edit config.json + install. Keys: kind (default ssh), host, run (shell: zsh on Macs, cmd.exe on Windows), short, label, conn, reconnect, timeout (60 default), restart_ok, verify_seconds, hung_note, part. | 'run' strings are long shell one-liners (ProPresenter newest version, Ableton last set from Live's Log.txt, Windows schtasks /Run \StatusPanel\Start X, etc.). | other campus: Per site, but most run strings are reusable verbatim if hosts and task names match.
|
||
|
|
- [config-key] config: watchdog :: network (NET key) settings @ config.network {interface en0, gateway 10.1.0.1, burst_connections 4, burst_groups 3, burst_window_seconds 10, remember_seconds 300} | today: Edit config.json + install. | gateway may be null (tests) to disable the gateway ping. | other campus: Per site.
|
||
|
|
- [config-key] config: watchdog :: alert_webhook (Companion unreachable 30 s) @ config.alert_webhook ''; status_panel.py:2333-2341 post_webhook | today: Edit config.json; empty = off. Posts {text} JSON (Slack-style). | URL string. | other campus: Per site.
|
||
|
|
- [hardcoded] hardcoded :: Colours and display levels @ status_panel.py:42-60 ORDER/COLORS (ok green 0x007A2E, warn amber, notice flashing amber, quiet, ack dark red, err red/black flash, off grey, idle, service blue, fixing blue, failed orange); make_page.py:35 PURPLE | today: Edit status_panel.py (no rebuild: colours travel in sp_state). | other campus: Same. | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded :: Fix cooldown 60 s, hold max age 15 s, auto-fix defaults @ status_panel.py:1041 run_fixes cooldown=60; :2338 HOLD_MAX_AGE=15 | today: Edit status_panel.py. | other campus: Same. | (need not be editable)
|
||
|
|
- [workflow-step] hardcoded :: Project folder on the MacBook and its layout @ /Users/christian/Documents/Status Indicators: status_panel.py, coremidi.py, netgear.py, atem_watch.js, atem_state.js, atem-reference.xml, config.json, make_page.py, push_page.py, nav_keys.py, nav_templates.json, nav_locations.json, install.sh, status-page.companionconfig, restart-page.companionconfig, README.md, remote-access/, tascam-quiet/, tests/, .claude/settings.local.json, .gitignore (__pycache__, *.pyc, .DS_Store) | today: All editing happens here; NA Ingest only receives copies. | other campus: Needs a sites/<campus>/ split or per-campus repos. | (need not be editable)
|
||
|
|
- [companion-side] runtime-data :: Companion custom variable values are not persisted @ README.md:130 ('persist' off) | today: On Companion restart the three variables start empty; the watchdog refills within a second; keys are purple until then. | other campus: Same. | (need not be editable)
|
||
|
|
- [workflow-step] workflow: order of operations :: Full change sequence for a layout change (today) @ README.md:137-171; guideline 16 | today: 1 edit config.json; 2 run tests; 3 python3 make_page.py; 4 scp files; 5 ssh install.sh; 6 python3 push_page.py (and --which restart); 7 python3 nav_keys.py if nav settings/pages changed; 8 verify tablet + log; 9 README; 10 git commit + push; 11 memory/artifact. Watchdog-only changes: 1,2,4,5,8,9,10. | Nothing stops this during a live Sunday service except the user (guideline 10). | other campus: Per site.
|
||
|
|
|
||
|
|
### Lens: Site-specific and layout-specific things that are HARD-CODED in .py/.js/.sh/.ps1/.swift files (or exist only as one-time setup outside the repo) rather than in config.json: what a second campus with similar-but-different gear would have to change by editing code today.
|
||
|
|
- [hardcoded] hardcoded: site names in status_panel.py :: "NA Ingest" in module docstring and check docstrings @ /Users/christian/Documents/Status Indicators/status_panel.py:2, :427, :449, :1701, :1749 | today: edit the .py, re-run install.sh | free text; cosmetic only | other campus: rename to the campus's Ingest Mac or make the wording generic ("this Mac") | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: site names in status_panel.py :: Auto-fix daily log header text: "(NA Ingest fixes these by itself on Sundays 06:30-13:30; ...)" @ /Users/christian/Documents/Status Indicators/status_panel.py:680-683 | today: edit AutoLog.write in status_panel.py, re-run install.sh | literal string; the window is duplicated here even though auto_fix.windows is config | other campus: machine name and window must be built from config (site name + auto_fix.windows) or the header lies at the other campus | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: site names in status_panel.py :: Auto-fix log line "NA Ingest's view of Dante or the Dante network" @ /Users/christian/Documents/Status Indicators/status_panel.py:1198-1202 | today: edit status_panel.py | literal string | other campus: use a configured site/machine name | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: site names in status_panel.py :: Webhook texts "NA Ingest: Companion is answering again." / "NA Ingest: Companion has not answered for 30 seconds." and the 30 s threshold @ /Users/christian/Documents/Status Indicators/status_panel.py:2431, :2437-2438 | today: edit status_panel.py (alert_webhook URL itself is config.json:26, empty today) | text + 30 s; payload format {"text": ...} (Slack-style) at :2338 | other campus: site name in the message; threshold and webhook URL per campus
|
||
|
|
- [hardcoded] hardcoded: logging/paths in status_panel.py :: Watchdog log path default ~/Library/Logs/status-panel.log (CLI --log) and rotation 1,000,000 bytes x 3 backups @ /Users/christian/Documents/Status Indicators/status_panel.py:2485, :2491; echoed by install.sh:60 | today: edit status_panel.py or pass --log in the LaunchAgent plist (install.sh) | path; int bytes; int count | other campus: same path works anywhere; the UI should show/tail it | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: logging/paths in status_panel.py :: Default --config = <script dir>/config.json and --data-dir = <script dir> @ /Users/christian/Documents/Status Indicators/status_panel.py:2481-2482 (install.sh:40-41 passes --data-dir) | today: CLI flags set by install.sh | paths | other campus: unchanged; a UI needs to know the live data dir (~/Library/Application Support/status-panel) | (need not be editable)
|
||
|
|
- [runtime-data] hardcoded: logging/paths in status_panel.py :: service-mode.json (ALARMS override state) in the data dir @ /Users/christian/Documents/Status Indicators/status_panel.py:2384 | today: written by the watchdog; filename fixed in code | {override, last_sched} | other campus: unchanged; UI could show current ALARMS state | (need not be editable)
|
||
|
|
- [runtime-data] hardcoded: logging/paths in status_panel.py :: dante-map.json (self-updating Dante name->ip->mac->switch/port/poe map) in the data dir @ /Users/christian/Documents/Status Indicators/status_panel.py:1839-1840, :1902-1906 | today: written by the watchdog every dante_map_seconds; filename fixed | {name: {ip, mac, switch, port, shared, poe, seen}} | other campus: unchanged mechanism; UI should display it (it is the only place the Dante wiring is visible)
|
||
|
|
- [runtime-data] hardcoded: logging/paths in status_panel.py :: atem-reference.json (generated from the restore .xml at start) in the data dir @ /Users/christian/Documents/Status Indicators/status_panel.py:2107, :2114-2115 | today: regenerated each watchdog start from atem.reference | {audio: {input/source: {mixOption, faderGain}}, camera: {cam/cat/param: [values]}} | other campus: unchanged; derived from that campus's restore file | (need not be editable)
|
||
|
|
- [config-default] hardcoded: logging/paths in status_panel.py :: Auto-fix log folder default ~/Desktop/Auto-Fix Logs, file name pattern "YYYY-MM-DD Weekday Auto-Fix.log", one-calendar-month retention @ /Users/christian/Documents/Status Indicators/status_panel.py:630, :637-663, :666, :775 | today: auto_fix.log_dir key exists in code but is not in config.json; pattern and retention are code | path (default ~/Desktop/Auto-Fix Logs); retention fixed at 1 month | other campus: other campus may want a different folder/retention; expose log_dir and retention
|
||
|
|
- [hardcoded] hardcoded: colours and display in status_panel.py :: COLORS table: 11 display levels (ok, warn, notice, quiet, ack, err, off, idle, service, fixing, failed) each with (bg,fg) for flash-on and flash-off phases @ /Users/christian/Documents/Status Indicators/status_panel.py:49-61 | today: edit the dict, re-run install.sh (no page re-import needed) | 24-bit RGB ints, e.g. ok 0x007A2E/0xFFFFFF, err 0xFF0000/0xFFFFFF then 0x000000/0xFF3030 | other campus: same by guideline (every key green/flashing red), but should be editable in one place
|
||
|
|
- [hardcoded] hardcoded: colours and display in status_panel.py :: ORDER / RANK level priority (off < ok < idle < warn < notice < quiet < ack < err) @ /Users/christian/Documents/Status Indicators/status_panel.py:45-46 | today: edit status_panel.py | ordered list | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: colours and display in status_panel.py :: Key text fitting: LINE_CAPACITY=145, LINE_HEIGHT=1.15, fit_size largest=30 smallest=12, 95% height budget @ /Users/christian/Documents/Status Indicators/status_panel.py:1331-1356 | today: edit constants | measured on Companion 5.0.7 web buttons for a Stream Deck XL key | other campus: a different surface (Mini/+/plus) or Companion build may need re-measuring | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: colours and display in status_panel.py :: Stale-watchdog size 20 and purple used by the page expressions when sp_hb is old @ /Users/christian/Documents/Status Indicators/make_page.py:35, :62, :65 | today: edit make_page.py, rebuild and re-import both pages | PURPLE 0x6A1B9A, fg 0xFFFFFF, size 20 | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: key wording in status_panel.py :: Hold-feedback texts: NOTHING TO FIX, NO AUTO FIX, JUST TRIED WAIT 1 MIN, CHECKING, FIXING, AUTO-FIXING, WAKING PC, FIX FAILED, RESTARTING, DONE, FAILED, JUST DONE WAIT 1 MIN, STARTING WAIT 1 MIN, RECORDING LEFT ALONE, NOTHING TO CLEAR, CLEARED @ /Users/christian/Documents/Status Indicators/status_panel.py:1045-1070, :1115-1145, :1269-1294 | today: edit status_panel.py | English literals, with their display seconds (4, 15, 20, 30, 60, 120, 180) | other campus: same unless the other campus wants other words/language | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: key wording in status_panel.py :: Rendered texts: ALL OK, "%d DOWN", "%d WARN", OK, OFF, ON, manual, HOLD TO FIX, HOLD 2s, "+%d" @ /Users/christian/Documents/Status Indicators/status_panel.py:1372-1421 | today: edit render() | "HOLD 2s" assumes make_page HOLD_MS=2000 | other campus: keep in sync with hold duration if it changes | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: key wording in status_panel.py :: Check fault words: NO DATA, NOT IN COMPANION, DISABLED, STARTING, WARNING, OFFLINE, NO DISK, FULL x, LOW x, NOT REC, <alias> GONE, <ch> BATT, <ch> INTERF, <ch> RF MUTE, NO PING, NOT LOADED, STOPPED, UNREACH, SPOTIFY CLOSED, NOT PLAYING, WRONG PLAYLIST, PLAYING, DISK nGB, NO SESSION, MIDI LOST, MIDI <state>, SILENT, LINK DOWN, NO GATEWAY, n DROPPED, BLIP HH:MM, CHECK BUG, "x%d" flapping @ /Users/christian/Documents/Status Indicators/status_panel.py:200-520, :616, :803, :817-860 | today: edit each check function | English literals; Shure channel names cut to 9 chars (:326), Tascam messages to 14 (:378,:382) | other campus: unchanged; a UI glossary should list them so operators can be taught | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: key wording in status_panel.py :: short_reason mapping of Companion messages (ETIMEDOUT/TIMED OUT/TIMEOUT -> NO ANSWER, ECONNREFUSED -> REFUSED, EHOSTUNREACH/ENETUNREACH/EHOSTDOWN -> UNREACHABLE, AUTH/LOGIN/PASSWORD/401/403 -> LOGIN) @ /Users/christian/Documents/Status Indicators/status_panel.py:186-195 | today: edit the tuple | pattern -> word | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Poller intervals: connections 1 s, variables 1 s, slow-variables 3 s, conn-hosts 60 s, spotify 3 s, pings 3 s, midi 0.5 s, system 10 s, bonjour 15 s, http 5 s, remote 10 s, dante-map 30 s @ /Users/christian/Documents/Status Indicators/status_panel.py:2304-2315 | today: edit start_pollers | seconds (float) | other campus: a campus with more SSH hosts or slower links may need different intervals
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Main loop: 2.5 s start grace, redraw every 0.5 s, sp_state rewritten at least every 10 s, loop sleep 0.25 s @ /Users/christian/Documents/Status Indicators/status_panel.py:2387, :2400, :2417, :2440 | today: edit run() | seconds | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Companion HTTP timeout 3 s; connections considered fresh for 10 s @ /Users/christian/Documents/Status Indicators/status_panel.py:83, :181 | today: edit Companion.__init__ / Snapshot.conns_fresh | seconds | other campus: unchanged | (need not be editable)
|
||
|
|
- [config-default] hardcoded: timing in status_panel.py :: Debounce overrides: network 0 s, midi_peer 1 s (per-check debounce_seconds key allowed); general debounce from config (default 3) @ /Users/christian/Documents/Status Indicators/status_panel.py:748, :882-884 | today: debounce_seconds in config.json or per check; midi/network specials are code | seconds | other campus: expose global and per-check debounce
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Remote-Mac MIDI report considered stale after 12 s (no verdict) @ /Users/christian/Documents/Status Indicators/status_panel.py:472 | today: edit check_midi_peer | 12 s | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Ping: /sbin/ping -c 1 -t 1 -q, 3 s subprocess timeout; a host alarms after 2 consecutive misses (ping check default failures=2; gateway fixed at 2) @ /Users/christian/Documents/Status Indicators/status_panel.py:396, :820, :1445-1449 | today: edit ping_once / check_ping (per-check "failures" key exists) | int misses; the -t 1 wait is macOS ping syntax | other campus: expose misses; Linux ping would need -W instead of -t
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Link check: /sbin/ifconfig <network.interface> must print "status: active" @ /Users/christian/Documents/Status Indicators/status_panel.py:1467-1472 | today: interface name is config (network.interface = en0); the method is code | interface name | other campus: en0 vs enX differs per Mac; the UI should list the Mac's interfaces to pick from
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Bonjour browse: /usr/bin/dns-sd -B _apple-midi._udp local. collected for 3 s @ /Users/christian/Documents/Status Indicators/status_panel.py:1510-1518 | today: edit poll_mdns | only RTP-MIDI instances can be an "mdns" check; other service types need code | other campus: a campus wanting to watch another Bonjour type (e.g. _dante) needs the type made configurable | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: HTTP checks: HEAD request, 6 s timeout, TLS unverified, any HTTP answer = OK; default interval 30 s @ /Users/christian/Documents/Status Indicators/status_panel.py:1521-1541, :2291 | today: interval_seconds per check is config; method/timeout are code | seconds | other campus: unchanged
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Hold freshness: HOLD_MAX_AGE 15 s (older queued holds are dropped) @ /Users/christian/Documents/Status Indicators/status_panel.py:2345 | today: edit constant | 15 s | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: timing in status_panel.py :: Fix cooldown 60 s per fix identity (holds, restart keys and auto-fix share it); auto_fix throttle 5 s; Dante-wide warning suppressed 600 s @ /Users/christian/Documents/Status Indicators/status_panel.py:1041, :1074, :1161, :1197, :1219, :1256 | today: edit defaults | seconds | other campus: expose cooldown
|
||
|
|
- [config-default] hardcoded: timing in status_panel.py :: auto_fix defaults in code: after_seconds 20, max_tries 2, retry_seconds 90, pause_after_network_seconds 60, forget_seconds 600, restart_connections, fixes list, windows @ /Users/christian/Documents/Status Indicators/status_panel.py:1164-1246 (config.json:98-105 sets most; forget_seconds only in code) | today: config.json auto_fix block, re-run install.sh | ints; windows [{days,start,end}]; fixes = list of fix ids that are 'gentle' | other campus: service times and gentle-fix list differ per campus
|
||
|
|
- [config-default] hardcoded: timing in status_panel.py :: network defaults in code: burst_connections 4, burst_groups 3, burst_window_seconds 10, remember_seconds 300, gateway, interface @ /Users/christian/Documents/Status Indicators/status_panel.py:815-865 (config.json:17-24) | today: config.json network block | ints, IP, interface | other campus: gateway and interface differ; thresholds may
|
||
|
|
- [config-default] hardcoded: timing in status_panel.py :: flap defaults: count 3 within window_seconds 600 @ /Users/christian/Documents/Status Indicators/status_panel.py:749-750 (config.json:15) | today: config.json flap | ints | other campus: same
|
||
|
|
- [config-default] hardcoded: check thresholds in status_panel.py :: HyperDeck defaults: full_minutes 5, low_minutes 30, rec_sync True, disk_service_only True, optional False; variables status/slotId/recordingTime/ip from Companion's hyperdeck module @ /Users/christian/Documents/Status Indicators/status_panel.py:254-289, :558-560 | today: per-check keys in config.json; variable names are code | minutes; booleans | other campus: a campus with decks 2 and 4 only: remove hd1/3/5/6 tiles from config AND the REC group members list; thresholds per deck
|
||
|
|
- [config-default] hardcoded: check thresholds in status_panel.py :: Shure defaults: channels 1, battery_err_bars 1, battery_warn_bars 2; variables ch_N_name / ch_N_battery_bars / ch_N_interference_status (shure-wireless module) @ /Users/christian/Documents/Status Indicators/status_panel.py:324-352, :565-568 | today: per-check keys; variable names are code | ints 0-5 | other campus: channel counts per receiver differ (4/4/1 at NA)
|
||
|
|
- [config-default] hardcoded: check thresholds in status_panel.py :: PSM defaults: channels 1, muted_is_error False; variable ch_N_rf_mute == MUTED @ /Users/christian/Documents/Status Indicators/status_panel.py:355-366, :569-571 | today: per-check keys | ints; bool | other campus: channel counts differ
|
||
|
|
- [hardcoded] hardcoded: check thresholds in status_panel.py :: Tascam: variables error/caution; OK strings "no error"/"no caution" @ /Users/christian/Documents/Status Indicators/status_panel.py:369-385, :563-564 | today: edit check_tascam | tascam-da-6400 module variable names | other campus: unchanged if same recorder | (need not be editable)
|
||
|
|
- [config-default] hardcoded: check thresholds in status_panel.py :: Disk defaults: err_gb 5, warn_gb 20 @ /Users/christian/Documents/Status Indicators/status_panel.py:456-465 | today: per-check keys (config.json:216 sets 25/8) | GB ints | other campus: same
|
||
|
|
- [hardcoded] hardcoded: check thresholds in status_panel.py :: Dante check: Companion variable "devices" (JSON list) and "<name>_ip" from the audinate-dantecontroller module; first dante check's conn is the one the map uses @ /Users/christian/Documents/Status Indicators/status_panel.py:292-321, :562, :1861-1866, :1880-1886 | today: edit code | module-specific variable names | other campus: unchanged if the same Companion Dante module is used | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: check thresholds in status_panel.py :: Art-Net listener: UDP 6454 on all interfaces with SO_REUSEPORT, magic "Art-Net\0", default max_silence_seconds 5 @ /Users/christian/Documents/Status Indicators/status_panel.py:510-520, :2184-2208 | today: source IP and max_silence per check in config; port in code | port 6454; seconds | other campus: source IP of the lighting PC differs
|
||
|
|
- [hardcoded] hardcoded: check thresholds in status_panel.py :: ATEM check: watcher report older than 30 s = no verdict; fix wait 8 s; watcher restart wait 5 s @ /Users/christian/Documents/Status Indicators/status_panel.py:2145, :2147, :2173 | today: edit code | seconds | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: check thresholds in status_panel.py :: midi_rx: "max_silence_seconds" only alarms while service mode is on; shows last-message age @ /Users/christian/Documents/Status Indicators/status_panel.py:496-507 | today: per-check key | seconds | other campus: source name differs ("Network NA Ingest Listen" is the NA session name)
|
||
|
|
- [hardcoded] hardcoded: check registry in status_panel.py :: CHECKS registry: conn, hyperdeck, dante, shure, psm, tascam, ping, launchd, process, http, disk, midi_peer, pref, spotify, mdns, midi_rx, remote, artnet, atem @ /Users/christian/Documents/Status Indicators/status_panel.py:534-539, :2181 | today: a new check type is Python code + a test | the UI's "add check" menu must offer exactly these with each one's keys | other campus: same set; a campus wanting e.g. a UniFi or OSC check needs code
|
||
|
|
- [hardcoded] hardcoded: check registry in status_panel.py :: Per-check keys the code understands: type, conn, fix (string or {sub: id, "*": id}), tag, name, msg, service_only, ignore_warning, optional, full_minutes, low_minutes, rec_sync, disk_service_only, ip, channels, battery_err_bars, battery_warn_bars, muted_is_error, host, failures, label, match, url, interval_seconds, path, warn_gb, err_gb, session, peer, address, domain, key, want, playlist, instance, source, max_silence_seconds, cmd, part, devices, count_all, debounce_seconds @ /Users/christian/Documents/Status Indicators/status_panel.py:244-531, :883, :987-999 | today: known only by reading the code | schema per check type; no JSON schema exists today | other campus: the UI must carry this schema so another campus can build checks without reading Python
|
||
|
|
- [hardcoded] hardcoded: check registry in status_panel.py :: RESTARTABLE check types (conn, hyperdeck, shure, psm, tascam) whose failing connection a hold restarts without a "fix" @ /Users/christian/Documents/Status Indicators/status_panel.py:542, :1005-1009; make_page.py:167 | today: edit tuple | tuple of type names | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: check registry in status_panel.py :: Reserved fix ids "restart-connection" and "dante-auto" @ /Users/christian/Documents/Status Indicators/status_panel.py:545, :549, :963-977 | today: edit constants | two magic strings a check's "fix" may name besides entries in "fixes" | other campus: UI fix picker must offer them
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: Fix kinds: ssh (default), local, atem, reconnect, midi_connect, netgear_poe, hyperdeck; and their keys host, run, short, label, timeout(60), reconnect, conn, restart_ok, part, verify_seconds(20), off_seconds(2), hung_note("STILL DOWN"), switch, port, mac @ /Users/christian/Documents/Status Indicators/status_panel.py:1921-2037 | today: fixes live in config.json; the kinds and their meaning are code | enum + per-kind schema | other campus: UI "add fix" must offer these kinds; a new kind (e.g. UniFi PoE) is code
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: "local" fixes run with /bin/zsh -c; "ssh" fixes run the raw string on the remote's default shell (cmd.exe on the Windows PCs) @ /Users/christian/Documents/Status Indicators/status_panel.py:1928 | today: edit code | shell choice | other campus: Windows fixes must be written in cmd syntax; a PowerShell-default sshd would break them | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: ssh exit 255 handling: with hosts[h].mac -> Wake-on-LAN and WAKING; else "<SHORT> NOT REACHABLE" @ /Users/christian/Documents/Status Indicators/status_panel.py:1932-1942 | today: edit code; mac/wake_broadcast per host in config | MAC, broadcast IP per host | other campus: each wakeable PC's MAC and subnet broadcast
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: Wake-on-LAN: UDP port 9, sends to wake_broadcast and 255.255.255.255 @ /Users/christian/Documents/Status Indicators/status_panel.py:1759-1769 | today: edit code | port 9 | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: reconnect_and_verify outcome strings: STILL OFF IN COMPANION, DISABLED IN COMPANION, STILL CONNECTING, NO NETWORK CHECK POWER, default hung_note STILL DOWN @ /Users/christian/Documents/Status Indicators/status_panel.py:2012, :2019, :2031, :2035, :2037 | today: edit code (hung_note per fix is config) | literals | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: hyperdeck_probe: control port 9993, 3 s, "transport info" protocol (present in code; no longer used by the hyperdeck fix kind) @ /Users/christian/Documents/Status Indicators/status_panel.py:1802-1834 | today: dead-ish code | port 9993 | other campus: n/a; candidate for removal or a 'probe' check type | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: fix engine in status_panel.py :: load_config validation: unknown check type/fix/host/member, duplicate ids, restart key ids, watch entries, and refusal of pkill/taskkill/killall in auto_fix fixes unless restart_ok @ /Users/christian/Documents/Status Indicators/status_panel.py:2234-2274 | today: the only validator; runs at start and in install.sh (JSON parse only) | rules | other campus: the UI must run the same validation before saving (R8)
|
||
|
|
- [hardcoded] hardcoded: tiles/layout logic in status_panel.py :: Tile keys the code understands: id, label, pos [row,col], kind (master | service | network), members [ids], checks [], hold_always (fix id); tiles without pos are hidden members @ /Users/christian/Documents/Status Indicators/status_panel.py:744-783, :1364-1423; make_page.py:151-192, :269-278 | today: config.json tiles; schema only in code | ids unique; members must be tile ids; pos must not collide (make_page.place raises) | other campus: the whole tiles list is the layout; UI needs a grid editor
|
||
|
|
- [hardcoded] hardcoded: tiles/layout logic in status_panel.py :: restart_page keys schema: page, page_name, jump_pos, back_pos, keys [{id, label, pos, fix, watch [fix ids or "conn:<label>"]}] @ /Users/christian/Documents/Status Indicators/status_panel.py:771, :1012-1027, :1256-1296, :1367-1376; make_page.py:131-148, :281-288 | today: config.json restart_page | restart key ids must not equal tile ids | other campus: different restart keys per campus
|
||
|
|
- [hardcoded] hardcoded: tiles/layout logic in status_panel.py :: Group tiles repeat members' faults; master counts detail tiles; service kind draws ON/OFF/manual; network kind draws link/gateway/burst @ /Users/christian/Documents/Status Indicators/status_panel.py:1383-1423, :815-865 | today: code | three special kinds | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: tiles/layout logic in status_panel.py :: Service windows / auto-fix windows day names DAYS = mon..sun, times "HH:MM" local, compared as strings @ /Users/christian/Documents/Status Indicators/status_panel.py:622, :689-693, :711-715 | today: config.json service_windows / auto_fix.windows | days list; "HH:MM"; end exclusive; no overnight windows | other campus: service times differ per campus
|
||
|
|
- [hardcoded] hardcoded: OS tools in status_panel.py :: Absolute tool paths: /sbin/ping, /sbin/ifconfig, /bin/launchctl, /usr/bin/pgrep, /usr/bin/defaults, /usr/bin/dns-sd, /usr/sbin/arp, /usr/bin/ssh, /usr/bin/osascript, /bin/zsh, /usr/bin/python3 (remote) @ /Users/christian/Documents/Status Indicators/status_panel.py:1447, :1469, :1478, :1488, :1494, :1511, :1632, :1636, :1708, :1741, :1750, :1857, :1928 | today: edit code | macOS paths | other campus: unchanged on any Mac; the Ingest machine must be a Mac | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: OS tools in status_panel.py :: launchd check reads `launchctl list` of the GUI user; process check uses pgrep -f <match>; pref check uses `defaults read <domain> <key>` @ /Users/christian/Documents/Status Indicators/status_panel.py:1475-1497 | today: labels/domains per check in config | LaunchAgent labels (org.waterschurch.* at NA), process paths, defaults domains | other campus: the Ingest Mac's own helper agents (resi bridge, captions, ProdCom, ProdDash) are NA-specific; another campus has its own list
|
||
|
|
- [companion-side] hardcoded: Companion API in status_panel.py :: Companion HTTP API paths: GET /api/connections, GET /api/variable/<label>/<name>/value, GET/POST /api/custom-variable/<name>/value (?value= to clear), POST /api/connections/<id>/restart|disable|enable @ /Users/christian/Documents/Status Indicators/status_panel.py:102-138 | today: code; Companion 5.0.7 API | host/port from config companion (127.0.0.1:8000 default at :2296) | other campus: same if the same Companion major version; the UI should show Companion version | (need not be editable)
|
||
|
|
- [companion-side] hardcoded: Companion API in status_panel.py :: Companion settings DB read: ~/Library/Application Support/companion/v<X.Y>/db.sqlite (newest), table instances, JSON field config.host, read-only, 2 s timeout (override key companion.db) @ /Users/christian/Documents/Status Indicators/status_panel.py:1552-1582 | today: companion.db key (not set) or code | path | other campus: Companion must run on the same Mac as the watchdog; schema may change with Companion versions | (need not be editable)
|
||
|
|
- [companion-side] hardcoded: Companion API in status_panel.py :: Custom variables sp_state / sp_hb / sp_cmd (names from config "variables") must be CREATED BY HAND in Companion; the API returns 404 for a missing one (code only logs "create it in Companion") @ /Users/christian/Documents/Status Indicators/status_panel.py:2418-2427; config.json:8 | today: Companion admin UI > Variables > Custom | three names | other campus: one-time step at every campus; the UI should detect and say which are missing
|
||
|
|
- [hardcoded] hardcoded: Companion API in status_panel.py :: Command protocol over sp_cmd: ack <tile>; ackall; service [on|off]; restart <tile> <unix>; force <key> <unix>; ';'-separated @ /Users/christian/Documents/Status Indicators/status_panel.py:2348-2376; make_page.py:83-97, :144-146, :166-182 | today: code on both sides | grammar | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: Spotify in status_panel.py :: AppleScript SPOTIFY_STATE: tell application "Spotify" ... player state, id/name/artist of current track; only when `pgrep -xq Spotify` (never opens it) @ /Users/christian/Documents/Status Indicators/status_panel.py:1593-1594, :1631-1641 | today: edit code | app name "Spotify" fixed; needs macOS Automation permission python3 -> Spotify (external) | other campus: a campus using Apple Music or another player needs a different check type | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: Spotify in status_panel.py :: Playlist reader: https://open.spotify.com/embed/playlist/<id> (__NEXT_DATA__, first 100 songs, anonymous token) then https://spclient.wg.spotify.com/playlist/v2/playlist/<id>?from=0&length=1000; UA Mozilla/5.0; refresh every 3600 s and on an unknown song after 60 s; last-3-songs rule @ /Users/christian/Documents/Status Indicators/status_panel.py:1597-1616, :1629, :1643, :156, :436-444 | today: edit code | undocumented Spotify endpoints; playlist must be public | other campus: same mechanism; fragile if Spotify changes its embed page | (need not be editable)
|
||
|
|
- [config-key] hardcoded: Spotify in status_panel.py :: Spotify playlist URI appears TWICE: check "playlist" and inside the spotify_play fix's run command (play track "spotify:playlist:2uTpJVYQLFnKF1WnSOuco8"), plus the name "Christian EDM 2026" in the fix label and check name @ /Users/christian/Documents/Status Indicators/config.json:75-76, :173; README.md:92, :123 | today: edit both places in config.json by hand, re-run install.sh | spotify:playlist:<22 chars> | other campus: one field in the UI must write both the check and the fix command (or the fix should read the check's playlist)
|
||
|
|
- [config-key] hardcoded: Spotify in status_panel.py :: spotify_play fix: pgrep Spotify || open -g -a Spotify; sleep 8; osascript play track; sleep 3; verify playing @ /Users/christian/Documents/Status Indicators/config.json:76 | today: config.json fixes.spotify_play.run | shell string with embedded AppleScript and the playlist URI | other campus: template it: UI generates the run string from playlist + delays
|
||
|
|
- [hardcoded] hardcoded: ATEM in status_panel.py :: MIX_OPTIONS Off=1 On=2 AudioFollowVideo=4 and CCU_PARAMS: the 13 camera settings compared (Lens/ApertureFstop, Video/ManualWhiteBalance, Exposure, DetailLevel, SensorGainInDecibels, SensorNDFilter, ColorCorrection Lift/Gamma/Gain/Offset/Contrast/LumaMix/ColorAdjust) with category/parameter ids and value order @ /Users/christian/Documents/Status Indicators/status_panel.py:2042-2058 | today: edit the dict | which camera settings count as 'wrong' | other campus: a campus that lets operators change e.g. iris live must drop ApertureFstop; should be a checklist in the UI
|
||
|
|
- [hardcoded] hardcoded: ATEM in status_panel.py :: Restore-file parser: expects ATEM Software Control XML with FairlightAudioMixer/AudioInput/AudioSource (mixOption, faderGain dB -> x100) and CameraControl entries (device, category, parameter, fields) @ /Users/christian/Documents/Status Indicators/status_panel.py:2061-2086 | today: code | XML schema of ATEM Software Control 9.x | other campus: unchanged for any ATEM with Fairlight; a classic-audio ATEM would need another parser | (need not be editable)
|
||
|
|
- [config-key] hardcoded: ATEM in status_panel.py :: atem config keys and their Companion-version-bound globs: node "/Applications/Companion [0-9]*.app/Contents/Resources/node-runtimes/node22/bin/node", library "~/Library/Application Support/companion/modules/bmd-atem-*/node_modules/atem-connection", reference "atem-reference.xml" (relative to script dir), host @ /Users/christian/Documents/Status Indicators/config.json:91-96; status_panel.py:2101-2115, :2089-2095 | today: config.json atem block | globs; newest version picked by numbers in the path | other campus: switcher IP differs; node22 / app-name globs break on a Companion upgrade; the UI should show which node/library resolved
|
||
|
|
- [external-setup] hardcoded: ATEM in status_panel.py :: atem-reference.xml: a copy of "4k plus 2026-10-07 14-59-55.xml" from Google Drive Backup/NA/ATEM (product "ATEM 4 M/E Constellation 4K Plus"), 1.6 MB committed to git, copied by install.sh @ /Users/christian/Documents/Status Indicators/atem-reference.xml; README.md:114; install.sh:28 | today: copy the new restore file over atem-reference.xml, re-run install.sh (watchdog rebuilds the JSON at start) | file upload | other campus: each campus has its own restore file; the UI needs an 'upload new restore file' action and shows its date/product
|
||
|
|
- [hardcoded] hardcoded: atem_watch.js :: CLI argv order <switcher ip> <atem-connection path> <reference.json>; report every 1 s, repeat every 10 s; float tolerance 0.002; MIX labels Off/On/AFV; CCdP command name; type 128 = float; disableMultithreaded @ /Users/christian/Documents/Status Indicators/atem_watch.js:13-21, :39, :76, :96-100, :113 | today: edit the .js, re-run install.sh | constants | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: atem_state.js :: Read-only snapshot tool: 15 s connect timeout, default 3 s CCU collection; not deployed by install.sh @ /Users/christian/Documents/Status Indicators/atem_state.js:6, :26, :39 | today: run by hand with Companion's node | argv <ip> <lib> [secs] | other campus: useful as a UI 'what does the switcher look like now' button | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: SSH in status_panel.py :: ssh_cmd options: -i <ssh_key> (default ~/.ssh/id_status_panel), BatchMode=yes, ConnectTimeout=5, IdentitiesOnly=yes, LogLevel=ERROR, StrictHostKeyChecking=accept-new, ControlMaster=auto, ControlPath=/tmp/status-panel-ssh-%C, ControlPersist=120; target string hosts[h].ssh @ /Users/christian/Documents/Status Indicators/status_panel.py:1748-1753 | today: ssh_key is config.json:28; the options are code | OpenSSH options | other campus: unchanged; the key file must exist on that campus's Ingest Mac | (need not be editable)
|
||
|
|
- [config-key] hardcoded: SSH in status_panel.py :: hosts schema: {alias: {ssh: "user@ip", mac?, wake_broadcast?}} (7 aliases at NA: prop, tracks, translation, bibletv, lighting, studiob, livestream) @ /Users/christian/Documents/Status Indicators/config.json:31-39; status_panel.py:1931-1935, :2254-2258 | today: config.json hosts | alias; user@host; MAC; broadcast | other campus: entirely per campus; these aliases are what fixes/checks/midi_peer refer to (R5 machine list)
|
||
|
|
- [hardcoded] hardcoded: SSH in status_panel.py :: Remote MIDI over SSH: coremidi.py source is sent over stdin to /usr/bin/python3 on the other Mac (streamed; ServerAliveInterval=2/CountMax=3; 0.5 s poll, 5 s keepalive print, 3 s reconnect wait; one-shot 20 s timeout; connect_peer 30 s) @ /Users/christian/Documents/Status Indicators/status_panel.py:1663-1746, :1959-1976 | today: code | requires macOS python3 + CoreMIDI on the remote Mac (Macs only; a Windows rtpMIDI host cannot be a midi_peer "host") | other campus: any Mac whose sessions are watched needs Remote Login on and the key authorized | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: SSH in status_panel.py :: remote checks batched per host every 10 s as one shell line "(cmd) >/dev/null 2>&1; echo SPn=$?" with 20 s timeout @ /Users/christian/Documents/Status Indicators/status_panel.py:1772-1799 | today: code | POSIX-sh syntax; would not work on a cmd.exe host | other campus: remote checks only for Macs/Linux today | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: Dante/Netgear in netgear.py :: SWITCHES default list ["10.66.1.100", "10.66.1.102"] used by the `lookup` CLI (the watchdog passes config dante_switches) @ /Users/christian/Documents/Status Indicators/netgear.py:21, :74 | today: edit netgear.py (duplicate of config.json:30) | list of IPs | other campus: other campus's switch IPs; CLI default should read config
|
||
|
|
- [secret] hardcoded: Dante/Netgear in netgear.py :: KEYCHAIN_SERVICE "netgear-status-panel" (login keychain item; account = switch username, e.g. admin) @ /Users/christian/Documents/Status Indicators/netgear.py:22-34 | today: once in Terminal on the Ingest Mac: security add-generic-password -s netgear-status-panel -a admin -w (never in files; only readable in the GUI session, so the watchdog must be a LaunchAgent) | service name fixed; username/password in keychain | other campus: one-time step per campus; the UI should show present/missing and the account name, never the password
|
||
|
|
- [hardcoded] hardcoded: Dante/Netgear in netgear.py :: Netgear M4250 CLI driver: telnet port 23, 8 s timeout, prompt regex [>#], User:/Password: prompts, `enable` with blank password, `terminal length 0`, commands show version / show mac-addr-table [interface X] / show poe port info X / configure / interface X / poe reset / logout @ /Users/christian/Documents/Status Indicators/netgear.py:37-68, :77-131 | today: code | vendor-specific | other campus: a campus on UniFi/Cisco/other PoE switches needs a different driver (fix kind netgear_poe and the map survey both depend on it) | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: Dante/Netgear in netgear.py :: MAX_SHARED = 2 (a port with more MACs is an uplink and is never power-cycled); port format \d+/\d+ @ /Users/christian/Documents/Status Indicators/netgear.py:118, :143, :185, :201 | today: edit constant | int | other campus: same; expose as a safety setting
|
||
|
|
- [external-setup] hardcoded: Dante/Netgear in status_panel.py :: Dante map survey uses this Mac's ARP cache (`arp -an`), i.e. the Ingest Mac must sit on the Dante VLAN (NA: Dante port en17, switch management via en20 10.66.1.2 per memory); those interfaces are not in config @ /Users/christian/Documents/Status Indicators/status_panel.py:1855-1858, :1869-1906; memory companion-status-page.md | today: physical/network setup; nothing to edit | interface names for display | other campus: the UI should show which interface reaches the Dante subnet and whether the switches answer
|
||
|
|
- [config-default] hardcoded: Dante/Netgear in status_panel.py :: dante_map_seconds default 600; first map attempted every 30 s until success; map entries kept forever for devices that vanish @ /Users/christian/Documents/Status Indicators/status_panel.py:1875-1877, :2315 | today: dante_map_seconds key (not in config.json) | seconds | other campus: same
|
||
|
|
- [hardcoded] hardcoded: coremidi.py :: NETWORK_DRIVERS = (com.apple.AppleMIDINetworkDriver, com.apple.AppleMIDIRTPDriver) - macOS 26.5 vs 26.2 names @ /Users/christian/Documents/Status Indicators/coremidi.py:57-59 | today: edit tuple | driver bundle ids | other campus: a Mac on another macOS release may need a third name; the UI should show 'no network MIDI driver found' clearly | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: coremidi.py :: CoreMIDI client/port names "status-panel" / "status-panel in"; LIVE_STATES running/connected; session property apple.midirtp.session / dns-sd-name; clock/active-sensing (0xF8/0xFE) ignored @ /Users/christian/Documents/Status Indicators/coremidi.py:120, :151, :163, :251, :300, :330 | today: code | constants | other campus: unchanged | (need not be editable)
|
||
|
|
- [config-key] hardcoded: coremidi.py :: midi_peer identity = (host alias, session name, peer name) + address "ip:5004" or Bonjour "\tName\tlocal." form; session and peer names are the human names set in Audio MIDI Setup / rtpMIDI ("NA Ingest", "NA Tracks", "NA ProP", "Lighting PC", "SuperRack-LiveBox", "Studio B Mac Studio") @ /Users/christian/Documents/Status Indicators/config.json:161-166; coremidi.py:171-193; status_panel.py:468-487, :993-1000 | today: config.json midi checks | session (must exist on that Mac), peer, address | other campus: all names/addresses differ; the UI should list live sessions/peers read from coremidi to pick from
|
||
|
|
- [hardcoded] config: layout in make_page.py :: EXPORT_VERSION 12 and COMPANION_BUILD "5.0.7+9763-stable-cec2f88e6f" written into every page export @ /Users/christian/Documents/Status Indicators/make_page.py:31-32, :257-259 | today: edit make_page.py, rebuild, re-import | must be acceptable to the campus's Companion | other campus: a campus on another Companion build may need these bumped; UI should read Companion's version and warn | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: GRID {minColumn 0, maxColumn 8, minRow 0, maxRow 5} in the page export (Stream Deck XL shows 8x4 of it) @ /Users/christian/Documents/Status Indicators/make_page.py:33, :260; README.md:10-16 | today: edit make_page.py | grid bounds | other campus: a campus with a different surface (Stream Deck +, Mini, two XLs) needs different bounds and a different tile map
|
||
|
|
- [hardcoded] config: layout in make_page.py :: STALE_SECONDS 15 (sp_hb older -> purple WATCHDOG DOWN) in the button expressions @ /Users/christian/Documents/Status Indicators/make_page.py:34, :53, :209 | today: edit, rebuild, re-import both pages and re-run nav_keys.py | seconds | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: HOLD_MS 2000 (hold duration for restart/force) and nav hold default 1000 ms / tap page 1 @ /Users/christian/Documents/Status Indicators/make_page.py:36, :144-146, :181-182, :199; config.json:6-7 (nav_hold_ms, nav_tap_page) | today: HOLD_MS is code (rebuild + re-import); nav values are config | ms | other campus: same by guideline; if changed, status_panel's "HOLD 2s" text must follow
|
||
|
|
- [companion-side] config: layout in make_page.py :: Stale texts "WATCHDOG\nDOWN\n<instance_errors> ERR" (master) and "<label>\n?" (others); uses $(internal:instance_errors) and $(custom:flash_tick) @ /Users/christian/Documents/Status Indicators/make_page.py:9, :61-62, :157, :161 | today: code; flash_tick custom variable + its 500 ms trigger must already exist in Companion | flash_tick must be created by hand at a new campus (trigger "flash_tick_500") | other campus: one-time Companion step; UI should detect a missing flash_tick
|
||
|
|
- [hardcoded] config: layout in make_page.py :: Button style: font companion-sans, outlineColor 4278190080, decoration border, fontsizeAllowShrink, per-key size from sp_state 's' @ /Users/christian/Documents/Status Indicators/make_page.py:66-80, :107-118 | today: edit, rebuild, re-import | Companion 5 layered-button fields | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: Static jump keys RESTART PAGE / STATUS PAGE: colour 0x37474F, white text, positions from restart_page.jump_pos / back_pos (both [2,6] at NA) @ /Users/christian/Documents/Status Indicators/make_page.py:274-277, :284-285; config.json:108 | today: colour/text in code; positions in config | pos; colour | other campus: positions depend on the campus's tile map
|
||
|
|
- [hardcoded] config: layout in make_page.py :: NAV_LOCATIONS pageup (0,0), pagenum (1,0), pagedown (2,0): column 0 is reserved for nav keys on both pages; NAV_MARKER "STATUS nav key" @ /Users/christian/Documents/Status Indicators/make_page.py:195-196, :238-245; push_page.py:122-123; nav_keys.py:29 | today: edit make_page.py (and the tile map must avoid those cells) | row/col tuples | other campus: Companion default; a campus that moved its nav keys needs this changed | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: nav_templates.json: Companion 5.0.7's converted UP / page number / DOWN keys captured from page 19 (ids like izGK69mOF_3K_vast-75-) @ /Users/christian/Documents/Status Indicators/nav_templates.json; make_page.py:207 | today: re-capture from Companion after 'convert to regular button' if the version changes | JSON blob | other campus: re-capture at a campus on a different Companion version | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: Hold decision per tile: hold exists only if a check is RESTARTABLE with a conn, or any check has a fix, or members, or hold_always, or kind network @ /Users/christian/Documents/Status Indicators/make_page.py:167-169 | today: code; a tile gaining/losing a hold requires rebuild + re-import | rule | other campus: UI must know when a config change needs a page re-import (R8)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: Button notes text mentioning "status_panel.py on NA Ingest" and "clears itself after 5 minutes" (remember_seconds is config) @ /Users/christian/Documents/Status Indicators/make_page.py:140-141, :171, :188 | today: code | help text seen in Companion's editor | other campus: site name; '5 minutes' should come from config | (need not be editable)
|
||
|
|
- [hardcoded] config: layout in make_page.py :: Output file names status-page.companionconfig / restart-page.companionconfig (gzipped JSON, committed to git) @ /Users/christian/Documents/Status Indicators/make_page.py:298-303; push_page.py:180-184 | today: python3 make_page.py | paths | other campus: per-site outputs would collide in one repo | (need not be editable)
|
||
|
|
- [companion-side] config: layout in make_page.py :: Companion internal action ids custom_variable_set_value and set_page (surfaceId self), command appended as plain text "$(custom:sp_cmd);<cmd>" @ /Users/christian/Documents/Status Indicators/make_page.py:83-103 | today: code | Companion 5 internals | other campus: unchanged | (need not be editable)
|
||
|
|
- [hardcoded] config: pages in push_page.py :: Defaults --host na-ingest.local, --port 8000; page/page_name from config (19 "19\nStatus", 20 "20\nRestart") @ /Users/christian/Documents/Status Indicators/push_page.py:172-173; config.json:3-4, :108 | today: CLI flags; config.json page numbers (page_name embeds the number so both must change together) | hostname; port; page ints | other campus: other campus's Ingest hostname and free page numbers
|
||
|
|
- [companion-side] config: pages in push_page.py :: Import mechanics: tRPC over WebSocket /trpc, importExport.prepareImport.start/uploadChunk(256 KB)/complete(sha1)/importSinglePage(sourcePage 1), 40 x 3 s retry on an open upload; GET /int/export/page/N; /api/variable/internal/page_number_N_name/value @ /Users/christian/Documents/Status Indicators/push_page.py:32, :103-134, :162-165, :195-224 | today: code; Companion 5.0.7 internal API | internal API | other campus: may break on a Companion upgrade; UI should fall back to 'import by hand' instructions | (need not be editable)
|
||
|
|
- [hardcoded] config: pages in push_page.py :: Safety rule: refuse to import unless the target page holds only nav keys or is already the page of that name (--force overrides) @ /Users/christian/Documents/Status Indicators/push_page.py:137-159, :191-193 | today: code | rule | other campus: UI must surface the refusal reason and never auto-force
|
||
|
|
- [hardcoded] config: pages in nav_keys.py :: Defaults --host na-ingest.local --port 8000; walks pages 1..N until export 404; copies from status page col 0 via controls.copyControl / controls.resetControl; ?includeSecrets=false @ /Users/christian/Documents/Status Indicators/nav_keys.py:32-33, :61-75, :81-82, :110-115 | today: CLI; run after every page move (guideline 9) | hostname; nav_keys list in config (pagenum only today) | other campus: page count and nav key positions differ
|
||
|
|
- [runtime-data] config: pages in nav_keys.py :: nav_locations.json: record of every page/row/col converted (96 entries at NA incl. the odd 15/0/1), committed to git @ /Users/christian/Documents/Status Indicators/nav_locations.json; nav_keys.py:28, :89, :121 | today: written by nav_keys.py | {"page/row/col": kind} | other campus: site-specific; must not be shared between campuses in one repo (UI: 'which pages were touched' view + revert button)
|
||
|
|
- [hardcoded] NA Ingest install: install.sh :: LaunchAgent label org.waterschurch.status-panel; plist ~/Library/LaunchAgents/<label>.plist; domain gui/<uid> @ /Users/christian/Documents/Status Indicators/install.sh:9, :12-13, :35 | today: edit install.sh | reverse-DNS label | other campus: another org/campus may want its own label; UI (R5) must show this agent's state on the Ingest Mac
|
||
|
|
- [hardcoded] NA Ingest install: install.sh :: DEST ~/Library/Application Support/status-panel (not ~/Documents: launchd python3 cannot read it); backup config.json.bak-<timestamp> only on install when changed @ /Users/christian/Documents/Status Indicators/install.sh:10-11, :24-26 | today: edit install.sh | path; one-shot .bak files (no history viewer) | other campus: same path; the UI's history/backups (R8) should live here
|
||
|
|
- [hardcoded] NA Ingest install: install.sh :: Deployed file list: status_panel.py coremidi.py netgear.py config.json atem_watch.js (+ atem-reference.xml if present); atem_state.js, make_page.py, push_page.py, nav_keys.py, nav_templates.json are NOT deployed @ /Users/christian/Documents/Status Indicators/install.sh:27-28 | today: edit the cp line whenever a file is added | file list | other campus: a UI server file must be added here, and page-building tools must be deployed if the UI runs on Ingest | (need not be editable)
|
||
|
|
- [hardcoded] NA Ingest install: install.sh :: Plist: /usr/bin/python3 status_panel.py --data-dir DEST; RunAtLoad; KeepAlive; ThrottleInterval 10; StandardErrorPath ~/Library/Logs/status-panel.err.log; bootout/wait-up-to-10 s/bootstrap x3 @ /Users/christian/Documents/Status Indicators/install.sh:30-58 | today: edit install.sh | launchd keys | other campus: unchanged | (need not be editable)
|
||
|
|
- [workflow-step] NA Ingest install: workflow :: Deploy path from the MacBook: scp files to checklist-ingest:status-panel-install/ then ssh checklist-ingest 'zsh ~/status-panel-install/install.sh'; the alias "checklist-ingest" lives in the user's own ~/.ssh/config (not in the repo) @ /Users/christian/Documents/Status Indicators/README.md:142, :148; .claude/settings.local.json; memory companion-status-page.md | today: by hand from the MacBook | ssh alias; staging folder name | other campus: each campus's Ingest needs its own alias; an on-Ingest UI removes the need to scp at all
|
||
|
|
- [workflow-step] NA Ingest install: workflow :: Page import workflow: python3 make_page.py -> push_page.py (--which restart) -> nav_keys.py; or by hand via Import/Export into page 19/20 (README says the file is on NA Ingest's Desktop) @ /Users/christian/Documents/Status Indicators/README.md:134, :157-163; make_page.py:19; push_page.py:12-14 | today: three commands on the MacBook against na-ingest.local | rebuild only when layout/hold-ability changed | other campus: UI 'Apply layout' button runs all three locally on Ingest
|
||
|
|
- [secret] NA Ingest install: external-setup :: NA Ingest SSH key ~/.ssh/id_status_panel (+.pub, comment status-panel@NA-Ingest) generated once by hand; config ssh_key points to it @ /Users/christian/Documents/Status Indicators/config.json:28; status_panel.py:1750; memory companion-status-page.md | today: ssh-keygen by hand on the Ingest Mac | private key never leaves Ingest; public key is copied into mac-authorize.sh / windows-setup.ps1 | other campus: new key per campus; UI should show the public key to paste and test each host
|
||
|
|
- [external-setup] NA Ingest install: external-setup :: macOS Automation permission: python3 (LaunchAgent) allowed to control Spotify (osascript) @ /Users/christian/Documents/Status Indicators/status_panel.py:1636 (implied); README/memory | today: macOS prompt once on the Ingest screen; System Settings > Privacy & Security > Automation | allowed/denied | other campus: one-time per campus; UI should test with a harmless osascript and report
|
||
|
|
- [external-setup] NA Ingest install: external-setup :: Keychain item netgear-status-panel must be stored in the Ingest login keychain (GUI session only) @ /Users/christian/Documents/Status Indicators/netgear.py:4-10 | today: security add-generic-password in Terminal on Ingest | present/absent | other campus: per campus (different switch login)
|
||
|
|
- [external-setup] NA Ingest install: external-setup :: NA Ingest's own DVS helper + sudoers (mac-dvs-helper.sh run on Ingest too) for the dvs_ingest local fix @ /Users/christian/Documents/Status Indicators/config.json:51; remote-access/mac-dvs-helper.sh:1 | today: ARD Send UNIX Command as root | installed/not | other campus: only if that campus's Ingest runs DVS
|
||
|
|
- [companion-side] NA Ingest install: external-setup :: Companion app itself on Ingest: pages 19/20 free, custom variables sp_state/sp_hb/sp_cmd/flash_tick, trigger flash_tick_500, connections with the labels config names, bmd-atem module installed, quiet Tascam module imported @ /Users/christian/Documents/Status Indicators/README.md:130-165; make_page.py:5-12; tascam-quiet/make_quiet_tascam.py:14-15 | today: Companion admin UI by hand | checklist | other campus: every item re-done per campus; UI should verify each (variables exist? labels exist? module versions?)
|
||
|
|
- [companion-side] Companion side: labels referenced by config :: Connection labels config refers to (HyperDeck_1..6, tascam, x32, audinate-dantecontroller, lighting-midi, Propresenter-API, ableton, BibleTV, ATEM, OBS-Youtube, RESI_Decoder, resi-studio-cues, VX1000, UHDJr, arena, Axient_1, Axient_2, ULXD-4, PSM_1..3) must match Companion's labels exactly (case-sensitive) @ /Users/christian/Documents/Status Indicators/config.json:135-237; status_panel.py:198-214 (NOT IN COMPANION) | today: rename in config.json to match Companion | strings | other campus: UI should offer a dropdown of live labels from GET /api/connections
|
||
|
|
- [hardcoded] Windows PC: windows-setup.ps1 :: $Key literal: NA Ingest's public key "ssh-ed25519 AAAAC3...thbgY status-panel@NA-Ingest"; the comment is also the grep marker @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:17, :52, :59 | today: edit the .ps1 before copying it to each PC | one public key | other campus: other campus's Ingest key; UI should generate this script with the right key filled in
|
||
|
|
- [hardcoded] Windows PC: windows-setup.ps1 :: $IngestIPs = 10.1.1.1, 10.6.3.222 (firewall RemoteAddress allowlist for port 22) @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:18, :46 | today: edit the .ps1 | list of IPs | other campus: that campus's Ingest addresses on every network it touches
|
||
|
|
- [hardcoded] Windows PC: windows-setup.ps1 :: App discovery list: OBS <drive>\Program Files\obs-studio\bin\64bit\obs64.exe (--disable-shutdown-check); Vista <drive>\Vista3\Vista.exe; Resolume Arena*\Arena.exe; Tobias Erichsen\rtpMIDI\rtpMIDI.exe; Bible app = first *.exe matching 'bible' (AtLogon PT15S) @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:64-82 | today: edit the .ps1 | name, exe candidates, args, at-logon flag | other campus: other PCs run other apps (e.g. ProPresenter on Windows, Chamsys); the UI should hold this app table and emit the script
|
||
|
|
- [hardcoded] Windows PC: windows-setup.ps1 :: Scheduled task folder \StatusPanel\ and names "Start OBS", "Start Vista", "Start Arena", "Start rtpMIDI", "Start BibleApp" - referenced verbatim by config fixes (schtasks /Run /TN "\StatusPanel\Start OBS" etc.) @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:102; config.json:57, :59, :61, :63, :65 | today: both files by hand | task names must agree in two places | other campus: UI should derive the fix's schtasks name from the app table
|
||
|
|
- [hardcoded] Windows PC: windows-setup.ps1 :: Elevated task when the exe has RUNASADMIN in AppCompatFlags\Layers (OBS on the LiveStream PC); otherwise Limited interactive principal; settings no time limit, IgnoreNew @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:83-108 | today: script logic | auto-detected | other campus: unchanged | (need not be editable)
|
||
|
|
- [external-setup] Windows PC: windows-setup.ps1 :: sshd: capability install, service Automatic + failure restart 5s/5s/30s; firewall rule OpenSSH-Server-In-TCP port 22 profile Any; keys written to C:\ProgramData\ssh\administrators_authorized_keys and %USERPROFILE%\.ssh\authorized_keys @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:21-61 | today: run once per PC as admin (needs the user's OK: system/firewall change) | done/not per PC | other campus: per PC per campus; UI shows per-PC status (ssh reachable? tasks exist?)
|
||
|
|
- [external-setup] Windows PC: windows-setup.ps1 :: rtpMIDIService failure-restart policy and Wake-on-LAN adapter setting (BIOS WoL must be enabled by hand) @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:112-125 | today: same script | per PC | other campus: per PC
|
||
|
|
- [workflow-step] Windows PC: windows-setup.ps1 :: Manual steps: save as C:\Users\<you>\windows-setup.ps1, PowerShell as admin, Set-ExecutionPolicy RemoteSigned -Scope CurrentUser, run, paste RESULT block back (pc, user, domain, sshd, nic/mac/ip, tasks) @ /Users/christian/Documents/Status Indicators/remote-access/windows-setup.ps1:1-14, :127-134 | today: by hand on each PC | RESULT block feeds hosts.<pc>.ssh user and .mac | other campus: UI should accept the RESULT block and fill hosts
|
||
|
|
- [hardcoded] Mac helpers: mac-authorize.sh :: Public key literal "ssh-ed25519 AAAAC3...thbgY status-panel@NA-Ingest" appended to the console user's ~/.ssh/authorized_keys via ARD Send UNIX Command as root; prints user/ComputerName/ssh-group @ /Users/christian/Documents/Status Indicators/remote-access/mac-authorize.sh:1-5 | today: edit the key in the file, paste into ARD | key; requires Remote Login on each Mac (com.apple.access_ssh) | other campus: other campus's key; UI generates the one-liner and records the printed user name into hosts
|
||
|
|
- [external-setup] Mac helpers: mac-dvs-helper.sh :: /usr/local/sbin/status-panel-dvs-start (defaults write /Library/Preferences/com.audinate.dante.dvs wantToRun 1; launchctl kickstart -k system/com.audinate.dante.DanteVirtualSoundcard) + /etc/sudoers.d/status-panel (<console user> NOPASSWD for that script only); target Macs listed in comment: NA ProPresenter Mac, NA Tracks, NA Translation, NA Ingest @ /Users/christian/Documents/Status Indicators/remote-access/mac-dvs-helper.sh:1-29 | today: paste into ARD as root on each DVS Mac | installed? (ls the two files over ssh) | other campus: any Mac running DVS at the other campus; path must match the dvs_* fixes' "sudo -n /usr/local/sbin/status-panel-dvs-start" in config.json:48-51
|
||
|
|
- [external-setup] Mac helpers: Studio B solo-mode agent :: install-solo-mode.sh: LABEL org.waterschurch.status-panel.solo-mode, DIR ~/Library/Application Support/status-panel, compiles with /usr/bin/swiftc (needs Xcode CLT on that Mac), scp/ssh target studiob@10.1.13.175 in the comment @ /Users/christian/Documents/Status Indicators/remote-access/install-solo-mode.sh:4-12 | today: scp + ssh by hand from Ingest | installed? agent running? (launchctl print over ssh) | other campus: only a campus with a Pro Tools room; host alias differs
|
||
|
|
- [hardcoded] Mac helpers: Studio B solo-mode agent :: solo-mode-agent.swift: bundle id com.avid.ProTools; menu path Options > Solo Mode > AFL* / Latch; state file solo-mode.json and trigger file solo-mode.fix in ~/Library/Application Support/status-panel; 1 s loop; needs Accessibility permission (prompted once on that Mac's screen) @ /Users/christian/Documents/Status Indicators/remote-access/solo-mode-agent.swift:15-17, :29, :34-41, :53-55, :86 | today: edit .swift, re-run install-solo-mode.sh | the two file paths are duplicated in config.json:69, :188-189 (remote checks + solo_afl fix) and must agree; 20 s staleness in config | other campus: menu titles differ per Pro Tools version/language; Accessibility is a per-Mac one-time step the UI should show as trusted/untrusted
|
||
|
|
- [workflow-step] tascam-quiet :: make_quiet_tascam.py: VERSION 1.3.1-quiet; stock module path ~/Library/Application Support/companion/modules/tascam-da-6400-1.3.0; two string patches anchored on the minified stock main.js; HELP.md note "Waters Church build"; output tascam-da-6400-1.3.1-quiet.tgz imported by hand in Companion > Modules @ /Users/christian/Documents/Status Indicators/tascam-quiet/make_quiet_tascam.py:9-10, :24-36, :56, :59 | today: run once, import package, pick 1.3.1-quiet on the tascam connection | module version selection is Companion-side | other campus: only a campus with a DA-6400; a newer stock module version breaks the patch anchors
|
||
|
|
- [hardcoded] .gitignore / repo hygiene :: .gitignore only ignores __pycache__/, *.pyc, .DS_Store: config.json, nav_locations.json, atem-reference.xml (1.6 MB), both .companionconfig outputs and .claude/settings.local.json are committed; dante-map.json / service-mode.json / .bak files exist only in the Ingest data dir @ /Users/christian/Documents/Status Indicators/.gitignore:1-3 | today: git | three patterns | other campus: one repo cannot hold two campuses' config.json/nav_locations.json/atem-reference.xml without per-site folders or branches; the UI's site identity must decide which files are per-site | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: data model gaps :: No site/campus name, Ingest hostname or machine display names anywhere in config (hosts have aliases only); machine names exist only in comments, README, button notes and log strings @ /Users/christian/Documents/Status Indicators/config.json:31-39; status_panel.py:2, :681; make_page.py:141, :188; remote-access/*:1-2 | today: n/a | needs a new top-level "site" block (name, ingest hostname, networks) and per-host display name/role/OS | other campus: this is the root of R3/R5: without it the UI cannot label machines or logs per campus
|
||
|
|
- [hardcoded] hardcoded: data model gaps :: No per-host inventory of what runs there (helpers, LaunchAgents, scheduled tasks, DVS helper, solo agent, sshd, WoL); that knowledge is spread across fixes' run strings, remote checks, the two helper scripts and the memory file @ /Users/christian/Documents/Status Indicators/config.json:41-89, :178-190; remote-access/* | today: in the user's head / README | needs hosts.<alias>.{os, role, helpers:[...], tasks:[...]} plus live probes (ssh ok? task exists? agent running?) | other campus: R5 requirement; each campus's map differs
|
||
|
|
- [hardcoded] hardcoded: data model gaps :: Duplicated values that must agree but are edited separately: Spotify URI (check + fix), schtasks names (ps1 + fixes), DVS helper path (sh + fixes), solo-mode paths (swift + checks + fix), switch IPs (netgear.py + config), public key (two scripts), page number (page + page_name), 5-minute blip text (make_page + remember_seconds), window text in AutoLog header @ see the individual items above | today: by hand in each place | single source of truth per value with generated outputs | other campus: the UI should own each value once and generate scripts/commands from it
|
||
|
|
|
||
|
|
### Lens: EVERY key of config.json and every key the code reads from it (status_panel.py, make_page.py, push_page.py, nav_keys.py), with type/default/validation, plus the hardcoded constants that change what those keys mean
|
||
|
|
- [config-key] config: companion :: companion.host @ config.json:2; status_panel.py:2296,1948,2000 | today: edit config.json, zsh install.sh (watchdog restarts) | string host/IP; default "127.0.0.1" (cfg["companion"].get("host")); no validation; the "companion" object itself is required (KeyError otherwise) | other campus: same value if the watchdog runs on the Companion Mac; NOTE push_page.py/nav_keys.py do NOT read it (they use --host na-ingest.local)
|
||
|
|
- [config-key] config: companion :: companion.port @ config.json:2; status_panel.py:2296,1948,2000 | today: edit config.json, zsh install.sh | int; default 8000; no validation | other campus: only if that site's Companion HTTP port differs
|
||
|
|
- [config-default] config: companion :: companion.db @ status_panel.py:1553-1560 (companion_db_path) | today: not set today; would be edit config.json, zsh install.sh | optional path (~ expanded) to Companion's db.sqlite; default = newest ~/Library/Application Support/companion/vN.N/db.sqlite; read read-only every 60 s for ping checks with "conn" and for reconnect_and_verify's ping; silently falls back to check "host" on any error | other campus: only if Companion keeps its data elsewhere
|
||
|
|
- [config-key] config: pages :: page @ config.json:3; make_page.py:242,278,284; push_page.py:182; nav_keys.py:86 | today: edit config.json, python3 make_page.py, python3 push_page.py (and --which restart), python3 nav_keys.py | int Companion page number (19); required; no validation (push_page refuses a target page that holds real buttons unless already this page) | other campus: each site picks a free page number
|
||
|
|
- [config-key] config: pages :: page_name @ config.json:4; make_page.py:278; push_page.py:182,188-190 | today: edit config.json, make_page.py, push_page.py | string, literal backslash-n for a line break on the key ("19\nStatus"); required; push_page.py refuses import if the built file's page name differs and uses it to recognise its own page | other campus: should match the page number
|
||
|
|
- [config-key] config: nav keys :: nav_keys @ config.json:5; make_page.py:240; nav_keys.py:88 | today: edit config.json, make_page.py, push_page.py, then python3 nav_keys.py (colours every page) / --revert | list of "pageup"|"pagenum"|"pagedown"; default all three when the key is absent; unknown names silently ignored; today ["pagenum"] | other campus: same
|
||
|
|
- [config-key] config: nav keys :: nav_hold_ms @ config.json:6; make_page.py:242,199 | today: edit config.json, make_page.py, push_page.py, nav_keys.py | int milliseconds; default 1000; hold on the page-number key jumps to the status page | other campus: same
|
||
|
|
- [config-key] config: nav keys :: nav_tap_page @ config.json:7; make_page.py:243,227 | today: edit config.json, make_page.py, push_page.py, nav_keys.py | int page number; default 1; tap on the page-number key (on release) goes there | other campus: site's home page
|
||
|
|
- [config-key] config: variables :: variables.state @ config.json:8; status_panel.py:2381,2418-2423; make_page.py:52,56,210 | today: edit config.json + create the custom variable in Companion by hand, make_page.py, push_page.py, install.sh | string custom-variable name ("sp_state"); required (KeyError); the variable must already exist in Companion or the watchdog logs "cannot set custom:... create it in Companion" and the page stays purple | other campus: same names fine; must be created in each Companion
|
||
|
|
- [config-key] config: variables :: variables.heartbeat @ config.json:8; status_panel.py:2424-2427; make_page.py:53,209 | today: same as variables.state | string ("sp_hb"); required; unix time written every redraw; page turns purple when older than 15 s (STALE_SECONDS) | other campus: same
|
||
|
|
- [config-key] config: variables :: variables.command @ config.json:8; status_panel.py:2395-2398; make_page.py:144,177,181 | today: same as variables.state | string ("sp_cmd"); required; buttons append "ack <id>" / "ackall" / "service toggle" / "restart <id> <unix>" / "force <id> <unix>" separated by ";" | other campus: same
|
||
|
|
- [companion-side] hardcoded: Companion side :: custom variable flash_tick + trigger flash_tick_500 @ make_page.py:9,61-62,211-212 ($(custom:flash_tick) == 1) | today: exists in Companion already (1 Hz blink clock); not configurable | hardcoded name; every key's flash phase depends on it; without it keys never flash | other campus: each site's Companion needs the same trigger/variable, or make the name a config key
|
||
|
|
- [config-key] config: windows :: service_windows @ config.json:10-12; status_panel.py:752,711-715 (ServiceMode.scheduled) | today: edit config.json, zsh install.sh | list of {days,start,end}; default [] (= never scheduled on; only the ALARMS button override); today every day 00:00-23:59 | other campus: per site; guideline says alarms any day so keep all-day
|
||
|
|
- [config-key] config: windows :: window shape: days / start / end (service_windows and auto_fix.windows) @ status_panel.py:622 (DAYS), 689-693 (in_windows), 711-715 | today: edit config.json, install.sh | days: list of lowercase "mon".."sun" (anything else never matches, no error); start/end: "HH:MM" strings compared as text, inside when start <= now < end (so "23:59" excludes the last minute; no overnight windows); no validation at all | other campus: per site service times
|
||
|
|
- [config-key] config: timing :: debounce_seconds @ config.json:14; status_panel.py:748,878-884 | today: edit config.json, install.sh | number of seconds a fault must persist before it is confirmed; default 3; overridden per check by check.debounce_seconds (midi_peer defaults to 1, network checks 0) | other campus: same
|
||
|
|
- [config-key] config: timing :: flap.count @ config.json:15; status_panel.py:749,615-616 | today: edit config.json, install.sh | int; default 3; that many confirmed fault starts inside flap.window_seconds shows amber "<msg> xN" | other campus: same
|
||
|
|
- [config-key] config: timing :: flap.window_seconds @ config.json:15; status_panel.py:750,606 | today: edit config.json, install.sh | int seconds; default 600 | other campus: same
|
||
|
|
- [config-key] config: network :: network.interface @ config.json:18; status_panel.py:2302,1467-1472 | today: edit config.json, install.sh | string interface name ("en0"); default none = no LINK DOWN check; ifconfig must print "status: active" | other campus: per Mac (en0 vs en1)
|
||
|
|
- [config-key] config: network :: network.gateway @ config.json:19; status_panel.py:818-820,2281-2282 | today: edit config.json, install.sh | IP string; default none = no NO GATEWAY check; pinged every 3 s, 2 misses = NO GATEWAY (hardcoded 2) | other campus: per site subnet
|
||
|
|
- [config-key] config: network :: network.burst_connections @ config.json:20; status_panel.py:844 | today: edit config.json, install.sh | int; default 4; watched Companion connections that must drop together (within burst_window_seconds) to call it a network burst | other campus: same
|
||
|
|
- [config-key] config: network :: network.burst_groups @ config.json:21; status_panel.py:844 | today: edit config.json, install.sh | int; default 3; distinct group tiles those drops must span | other campus: same
|
||
|
|
- [config-key] config: network :: network.burst_window_seconds @ config.json:22; status_panel.py:839 | today: edit config.json, install.sh | int seconds; default 10 | other campus: same
|
||
|
|
- [config-key] config: network :: network.remember_seconds @ config.json:23; status_panel.py:857 | today: edit config.json, install.sh | int seconds; default 300; how long NET shows the flashing "BLIP HH:MM" after a burst clears (hold NET clears it early) | other campus: same
|
||
|
|
- [config-key] config: alerts :: alert_webhook @ config.json:26; status_panel.py:2334-2342,2431,2438 | today: edit config.json, install.sh | URL string; "" or absent = off; POST JSON {"text": ...} when Companion has not answered for 30 s and when it answers again; message text hardcoded "NA Ingest: ..." | other campus: per site URL; the "NA Ingest" wording needs a site-name key
|
||
|
|
- [config-key] config: ssh :: ssh_key @ config.json:28; status_panel.py:1750 | today: edit config.json, install.sh; the key itself made once (remote-access/mac-authorize.sh) | path string, ~ expanded; default "~/.ssh/id_status_panel"; used with BatchMode=yes IdentitiesOnly=yes for every ssh | other campus: same path per ingest Mac; a new key pair per site
|
||
|
|
- [config-key] config: dante :: dante_switches @ config.json:30; status_panel.py:1872,1913; netgear.py:174,193 | today: edit config.json, install.sh; switch login stored once in keychain | list of switch IP strings; absent/empty = Dante map and PoE power-cycle off (dante-auto then only restarts the Companion connection); telnet port 23 hardcoded | other campus: per site switches; netgear.py's own SWITCHES list (netgear.py:21) is only for its CLI
|
||
|
|
- [config-default] config: dante :: dante_map_seconds @ status_panel.py:1877 | today: not set; edit config.json, install.sh | int seconds between switch surveys; default 600; the poller runs every 30 s regardless | other campus: same
|
||
|
|
- [config-key] config: hosts :: hosts (map alias -> machine) @ config.json:31-39; status_panel.py:1753,1931,2255,2257 | today: edit config.json, install.sh; plus one-time ssh authorisation on that machine | object keyed by alias (prop, tracks, translation, bibletv, lighting, studiob, livestream); aliases referenced by fixes.<id>.host, remote checks' host, midi_peer checks' host | other campus: the core per-site list; every machine the panel talks to
|
||
|
|
- [config-key] config: hosts :: hosts.<alias>.ssh @ config.json:32-38; status_panel.py:1753 | today: edit config.json, install.sh | "user@host" string; required for every alias; validated to exist only for ssh-kind fixes referenced by a tile check (:2254-2256) and remote checks (:2257); a midi_peer "host" or a restart-page-only ssh fix with a missing alias fails at runtime (KeyError in ssh_cmd) | other campus: per site users/IPs
|
||
|
|
- [config-key] config: hosts :: hosts.<alias>.mac @ config.json:38; status_panel.py:1931-1937,1759-1769 | today: edit config.json, install.sh | MAC string (any separator); optional; when an ssh fix exits 255 a Wake-on-LAN packet is sent and the key says WAKING PC; wake_on_lan raises ValueError if not 6 bytes (fix then reports FAILED) | other campus: per PC that may be asleep
|
||
|
|
- [config-key] config: hosts :: hosts.<alias>.wake_broadcast @ config.json:38; status_panel.py:1935,1767 | today: edit config.json, install.sh | IP string; optional; packet also always goes to 255.255.255.255; UDP port 9 hardcoded | other campus: per site subnet broadcast
|
||
|
|
- [config-key] config: fixes :: fixes (map id -> fix) @ config.json:41-89; status_panel.py:983,1100,1924,2252-2273 | today: edit config.json, install.sh | object keyed by fix id; ids referenced by check.fix, tile.hold_always, auto_fix.fixes, restart_page.keys[].fix and .watch; load_config checks every reference exists | other campus: largely reusable; host aliases and app names differ
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.kind @ status_panel.py:1925,1927-1987 | today: edit config.json, install.sh | string; default "ssh"; allowed ssh | local | atem | reconnect | midi_connect | netgear_poe | hyperdeck; an unknown kind logs a warning and the key shows FIX FAILED; NOT validated by load_config | other campus: same
|
||
|
|
- [config-key] config: fixes :: fix kind = ssh (fields) @ status_panel.py:1927-1952 | today: edit config.json, install.sh | uses host (required, hosts alias), run (required), timeout (60), reconnect (false), conn, short, label, restart_ok; runs `ssh <hosts.alias.ssh> '<run>'` in the remote login shell (cmd.exe on Windows PCs); exit 255 + hosts.mac -> WAKING, exit 255 otherwise -> "<SHORT> NOT REACHABLE"; exit 0 = success | other campus: same mechanics
|
||
|
|
- [config-key] config: fixes :: fix kind = local (fields) @ status_panel.py:1928-1952 | today: edit config.json, install.sh | uses run (required), timeout (60), reconnect (false), conn, short, label, restart_ok; runs `/bin/zsh -c <run>` on the ingest Mac as the logged-in user | other campus: same
|
||
|
|
- [config-key] config: fixes :: fix kind = atem (fields) @ status_panel.py:1953-1956,2147-2164 | today: edit config.json, install.sh | uses part (required: "audio"|"camera"), short, label; sends "fix <part>" to atem_watch.js and waits up to 8 s (hardcoded) for the switcher to match the restore file; fails if the ATEM watcher is not running | other campus: needs that site's atem section
|
||
|
|
- [config-key] config: fixes :: fix kind = reconnect (fields) @ status_panel.py:1957-1958,1993-2037 | today: edit config.json, install.sh | uses conn (required Companion label), verify_seconds (20), hung_note ("STILL DOWN"), short, label; restarts the Companion connection (or enables it if disabled), waits verify_seconds, then True if good, "STILL CONNECTING" if still starting, hung_note if the device still pings, else "NO NETWORK CHECK POWER" | other campus: same
|
||
|
|
- [config-key] config: fixes :: fix kind = midi_connect (fields) @ status_panel.py:1959-1976,993-1000,1107-1112 | today: edit config.json, install.sh | no fields of its own beyond short/label; session, peer, host and address come from the midi_peer check it is attached to; address = where the peer was last seen else check.address; local via coremidi.connect_peer, remote via ssh + /usr/bin/python3 - ; ok when result is asked|already|kicked; several run one after another | other campus: same
|
||
|
|
- [config-key] config: fixes :: fix kind = netgear_poe (fields) @ status_panel.py:1977-1982; netgear.py:110 | today: not used in config.json today; edit config.json, install.sh | uses switch (required IP), port (required "0/14" form), mac (optional expected MAC; refuses if that MAC is elsewhere); power-cycles one PoE port over telnet with the keychain login | other campus: per site switch/port
|
||
|
|
- [config-key] config: fixes :: fix kind = hyperdeck (fields) @ status_panel.py:1983-1986,981-992,1057-1063,1271-1272 | today: edit config.json, install.sh | uses verify_seconds (20), off_seconds (2), hung_note, short, label; conn and ip come from the hyperdeck check (ip: check.ip, else Companion variable "ip", else last remembered); disables then enables the Companion connection; per-deck 60 s cooldown; never runs while that deck is recording; never reboots the deck | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.host @ status_panel.py:1928,1931,1936,1942,2254-2256 | today: edit config.json, install.sh | hosts alias string; required when kind is ssh (default kind); validated only when the fix is referenced from a tile check; fixes used only by restart_page keys or hold_always are not validated (runtime KeyError -> FIX FAILED) | other campus: per site alias
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.run @ status_panel.py:1928,2264 | today: edit config.json, install.sh | shell command string; required for ssh/local; remote shell for ssh, /bin/zsh -c for local; if the fix is in auto_fix.fixes it must not contain pkill|taskkill|killall unless restart_ok is true (load_config raises); today also embeds site data: app names, LaunchAgent labels, \StatusPanel\ task names, the Spotify playlist URI, /usr/local/sbin/status-panel-dvs-start | other campus: commands change per site; the UI should expose the embedded values (playlist, labels, task names) as fields
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.timeout @ config.json:81,83; status_panel.py:1929 | today: edit config.json, install.sh | seconds; default 60; ssh/local only; subprocess killed after it (fix reports FAILED) | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.short @ config.json:42-88; status_panel.py:1102,1106,1112,1942 | today: edit config.json, install.sh | short key text; default fix id upper-cased; shown as "FIXING <short>" / "<SHORT> NOT REACHABLE"; on a group button prefixed to the outcome | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.label @ status_panel.py:1101,1253,1281,1925; make_page.py:173 | today: edit config.json, install.sh (+ make_page/push_page for hold_always notes) | plain-words description; default fix id in the watchdog (logs, auto-fix log); REQUIRED by make_page.py for any fix used as a tile's hold_always (KeyError otherwise) | other campus: wording mentions site machines ("NA Translation"); per site
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.reconnect @ config.json:58,60,81; status_panel.py:1945-1951 | today: edit config.json, install.sh | bool; default false; ssh/local only: after exit 0 restart the Companion connection named by the check's conn, else fixes.<id>.conn | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.conn @ config.json:81,85; status_panel.py:1945,1998-2001 | today: edit config.json, install.sh | Companion connection label; required for kind reconnect; fallback target for reconnect:true when the check has no conn; ignored by kind hyperdeck (uses the check's conn); not validated against Companion | other campus: per site connection labels
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.restart_ok @ config.json:72; status_panel.py:2264 | today: edit config.json, install.sh | bool; default false; lets a run containing pkill/taskkill/killall be listed in auto_fix.fixes (atem_midi today) | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.part @ config.json:70-71; status_panel.py:1954 | today: edit config.json, install.sh | "audio"|"camera"; required for kind atem; not validated (anything else just never matches) | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.verify_seconds @ config.json:85,87; status_panel.py:2023,2030 | today: edit config.json, install.sh | seconds; default 20; reconnect and hyperdeck kinds: wait before judging the connection | other campus: same
|
||
|
|
- [config-default] config: fixes :: fixes.<id>.off_seconds @ status_panel.py:2009 | today: not set; edit config.json, install.sh | seconds; default 2; hyperdeck kind: time the connection stays disabled before re-enabling | other campus: same
|
||
|
|
- [config-key] config: fixes :: fixes.<id>.hung_note @ config.json:85,87; status_panel.py:2035 | today: edit config.json, install.sh | key text (\n allowed); default "STILL DOWN"; shown when the connection is still bad but the device answers ping | other campus: same
|
||
|
|
- [config-default] config: fixes :: fixes.<id>.switch / .port / .mac (netgear_poe) @ status_panel.py:1980 | today: not set today | switch: IP string required; port: "unit/port" string required; mac: optional MAC guard; no load-time validation | other campus: per site
|
||
|
|
- [config-key] config: fixes :: special fix id "restart-connection" (RESTART_CONNECTION) @ status_panel.py:545,972-977,1005-1009,2252 | today: use the literal string as a check's fix (or a dict value); install.sh | allowed in check.fix instead of a fixes entry; restarts the check's own Companion connection (needs check.conn); checks of type conn/hyperdeck/shure/psm/tascam (RESTARTABLE :542) get this automatically when they have no fix | other campus: same
|
||
|
|
- [config-key] config: fixes :: special fix id "dante-auto" (DANTE_AUTO) @ config.json:151; status_panel.py:549,963-971,1909-1918 | today: edit config.json, install.sh | allowed in check.fix (dante checks); if dante-map.json says the device is on a PoE port (found by MAC) its port is power-cycled, else falls back to restart-connection on the Dante connection; one PoE cycle per MAC per plan | other campus: needs dante_switches + keychain login
|
||
|
|
- [config-key] config: fixes :: check.fix as a per-sub map {sub: fix id, "*": fallback} @ config.json:135,149-151; status_panel.py:961-962,1021-1022,2250-2253 | today: edit config.json, install.sh | keys are the check's sub-result names: dante = device names; hyperdeck = conn|disk|rec; shure = chN_batt|chN_rf; psm = chN_mute; tascam = conn|error|caution; "*" matches every other sub; each value validated like a string fix | other campus: dante device names differ per site
|
||
|
|
- [hardcoded] config: fixes :: implicit "enable" plan for a disabled Companion connection @ status_panel.py:953-959,1083-1088 | today: not configurable | any failing check whose conn is disabled in Companion is fixed by enabling it (TURN ON), never by its fix; good to document in the UI | other campus: same | (need not be editable)
|
||
|
|
- [config-key] config: tiles :: tiles (list) @ config.json:126-238; status_panel.py:747,755-760; make_page.py:271-273 | today: edit config.json, make_page.py, push_page.py, install.sh | ordered list of tile objects; order matters only for rendering/iteration; today 7 groups + 1 master + service + network + 25 detail tiles (6 hidden RF tiles) | other campus: the main per-site layout
|
||
|
|
- [config-key] config: tiles :: tiles[].id @ status_panel.py:2238-2241,2267; make_page.py:56-65 (jsonpath $.<id>.x) | today: edit config.json, make_page.py, push_page.py, install.sh | string; required; unique among tiles and not equal to any restart key id (validated); used as a JSON key in sp_state and inside Companion jsonpath expressions, so it must be a plain identifier (letters/digits/_) - NOT validated; the master tile's id must be "all" (make_page.py:210 nav keys read $.all.*, status_panel.py:2357 ackall acks "all") | other campus: same
|
||
|
|
- [config-key] config: tiles :: tiles[].label @ status_panel.py:886,1381,1385,1407-1421; make_page.py:154 | today: edit config.json, make_page.py, push_page.py, install.sh | string; required; first line of the key, prefix of fault messages ("VISTA SILENT"), name in logs; keep short (fit_size shrinks text to 12%) | other campus: same
|
||
|
|
- [config-key] config: tiles :: tiles[].pos @ config.json:127-224; make_page.py:272,248-252; status_panel.py:2466-2475 | today: edit config.json, make_page.py, push_page.py | [row, col] ints; optional - a tile without pos is hidden and only shows through a group's members (axient1.., psm1..); make_page raises on two buttons at one position; grid is GRID minColumn 0..8, minRow 0..5 (make_page.py:33); column 0 rows 0-2 are the nav keys; restart_page.jump_pos also occupies a slot; no range validation | other campus: per site Stream Deck layout
|
||
|
|
- [config-key] config: tiles :: tiles[].kind @ config.json:127,192,208; status_panel.py:912,1042,1383,1388; make_page.py:155-171 | today: edit config.json, make_page.py, push_page.py, install.sh | absent (normal/group) | "master" (ALL: press = ackall, shows ALL OK / N DOWN, no hold) | "service" (ALARMS toggle, press = service toggle) | "network" (NET: link/gateway/burst, hold clears a blip); not validated; exactly one of each expected | other campus: same
|
||
|
|
- [config-key] config: tiles :: tiles[].members @ config.json:128-133; status_panel.py:756,914,942,1402,2246-2248 | today: edit config.json, make_page.py, push_page.py, install.sh | list of tile ids; validated to exist; makes a group button (worst member, "+N"); hold fixes every member; a tile may be in several groups (first match wins for burst grouping) | other campus: per site
|
||
|
|
- [config-key] config: tiles :: tiles[].checks @ config.json:135-237; status_panel.py:789-810,2242-2244 | today: edit config.json, install.sh (make_page/push_page only if the hold-ability changes) | list of check objects; each type must be in CHECKS (19 types); a tile with checks or kind network is a "detail" tile counted by ALL; a check that throws shows CHECK BUG | other campus: per site
|
||
|
|
- [config-key] config: tiles :: tiles[].hold_always @ config.json:135-141,172; status_panel.py:1053-1063,2259-2260; make_page.py:169,173 | today: edit config.json, make_page.py, push_page.py, install.sh | fix id; validated to exist; hold runs it even when the button is green (HD1-6, TASCAM, SPOTIFY); for a hyperdeck-kind fix the first check with a conn supplies conn/ip and a recording deck is left alone; make_page needs fixes[hold_always].label | other campus: same
|
||
|
|
- [config-key] config: checks (common) :: checks[].type @ status_panel.py:534-539,2181,2243 | today: edit config.json, install.sh | one of conn, hyperdeck, dante, shure, psm, tascam, ping, launchd, process, http, disk, midi_peer, pref, spotify, mdns, midi_rx, remote, artnet, atem; validated | other campus: same
|
||
|
|
- [config-key] config: checks (common) :: checks[].conn @ status_panel.py:245,259,294,331,357,370,391,760,932,953,2256 | today: edit config.json, install.sh | Companion connection label (case-sensitive, as shown in Companion); required for conn/hyperdeck/dante/shure/psm/tascam, optional for ping; any check with conn is a "watched" connection for burst detection and gets the enable/restart plans; NOT validated against Companion (shows NOT IN COMPANION live) | other campus: per site labels; the UI should list Companion's live connections to pick from
|
||
|
|
- [config-key] config: checks (common) :: checks[].fix @ status_panel.py:960-962,1020-1022,2250-2256; make_page.py:167 | today: edit config.json, install.sh (+ make_page/push_page when it changes whether the key has a hold) | fix id string | "restart-connection" | "dante-auto" | per-sub dict; validated; absent = restart its Companion connection for RESTARTABLE types, nothing otherwise (hold says NO AUTO FIX) | other campus: same
|
||
|
|
- [config-key] config: checks (common) :: checks[].tag @ config.json:161-167,179-187,201,219-220; status_panel.py:805-808 | today: edit config.json, install.sh | string; optional; prefixed to fault text that does not already name its device ("PROPRES OFFLINE"); use on tiles with several devices | other campus: same
|
||
|
|
- [config-key] config: checks (common) :: checks[].service_only @ config.json:199; status_panel.py:245,313,398,1306 | today: edit config.json, install.sh | bool; default false; read only by conn, dante, ping; the fault shows grey "idle" while ALARMS is off instead of dark red "quiet" | other campus: same
|
||
|
|
- [config-default] config: checks (common) :: checks[].debounce_seconds @ status_panel.py:882-884 | today: not set; edit config.json, install.sh | seconds; default = global debounce_seconds (3), except midi_peer = 1; network sub-checks always 0 | other campus: same
|
||
|
|
- [config-key] config: check conn :: conn.ignore_warning @ config.json:179; status_panel.py:246-250 | today: edit config.json, install.sh | bool; default false; treats Companion's yellow "warning" state as OK (ProPresenter API flicker); error/offline/disabled still alarm | other campus: same
|
||
|
|
- [hardcoded] config: check conn :: conn fault texts (hardcoded) @ status_panel.py:186-214 | today: edit source | NO DATA (no Companion data for 10 s), NOT IN COMPANION, DISABLED (warn), NO ANSWER/REFUSED/UNREACHABLE/LOGIN mapped from the module message, OFFLINE, WARNING, STARTING | other campus: same | (need not be editable)
|
||
|
|
- [config-key] config: check hyperdeck :: hyperdeck.conn + polled variables @ status_panel.py:254-289,558-560 | today: edit config.json, install.sh | Companion label (HyperDeck_1..6); reads module variables status, slotId, recordingTime every 1 s and ip every 3 s; conn must be a Blackmagic HyperDeck module instance | other campus: use only the decks that site has (e.g. HyperDeck_2 and _4) - just list fewer tiles
|
||
|
|
- [config-key] config: check hyperdeck :: hyperdeck.optional @ config.json:136,138; status_panel.py:267-270 | today: edit config.json, install.sh | bool; default false; true = a deck with no disk/no recordingTime sits grey "NO DISK" with no alarm and is excluded from REC sync until a disk is in | other campus: per site
|
||
|
|
- [config-default] config: check hyperdeck :: hyperdeck.disk_service_only @ status_panel.py:272 | today: not set; edit config.json, install.sh | bool; default true; NO DISK on a non-optional deck is idle outside service | other campus: same
|
||
|
|
- [config-default] config: check hyperdeck :: hyperdeck.full_minutes @ status_panel.py:276 | today: not set; edit config.json, install.sh | int minutes left; default 5; below = red "FULL <left>" | other campus: same
|
||
|
|
- [config-default] config: check hyperdeck :: hyperdeck.low_minutes @ status_panel.py:278 | today: not set; edit config.json, install.sh | int minutes left; default 30; below = amber "LOW <left>" | other campus: same
|
||
|
|
- [config-default] config: check hyperdeck :: hyperdeck.rec_sync @ status_panel.py:283-287,794-796 | today: not set; edit config.json, install.sh | bool; default true; when any rec_sync deck is recording, every other rec_sync deck that is not shows red NOT REC | other campus: same
|
||
|
|
- [config-default] config: check hyperdeck :: hyperdeck.ip @ status_panel.py:987,1062,1986 | today: not set; edit config.json, install.sh | IP string; optional override of the deck's address used by the hyperdeck fix's ping; default = Companion variable "ip" of the connection, remembered if it disappears | other campus: normally not needed
|
||
|
|
- [config-key] config: check dante :: dante.conn + polled variables @ status_panel.py:292-303,562,1880-1886 | today: edit config.json, install.sh | Companion label of the audinate-dantecontroller module; reads variable "devices" (JSON list) every 1 s and "<name>_ip" for the Dante map; only the FIRST dante check's conn feeds the Dante map (dante_label) | other campus: same module per site
|
||
|
|
- [config-key] config: check dante :: dante.devices @ config.json:152-158; status_panel.py:304-313,791 | today: edit config.json, install.sh | dict {Dante device name: short alias} or list of names (alias = name); required; each missing device = red "<ALIAS> GONE"; count "seen/total" shown when >1 device; aliases should be short (14 chars) | other campus: the per-site Dante device list; the UI should offer the live list from Companion's devices variable
|
||
|
|
- [config-default] config: check dante :: dante.count_all @ status_panel.py:314-318 | today: not set; edit config.json, install.sh | bool; default false; true = the count covers every Dante device watched on any tile (so several dante checks can split devices across tiles) | other campus: same
|
||
|
|
- [config-key] config: check shure :: shure.conn + polled variables @ status_panel.py:329-352,565-568 | today: edit config.json, install.sh | Companion label of a Shure module (Axient_1, Axient_2, ULXD-4); reads ch_N_name, ch_N_battery_bars, ch_N_interference_status every 3 s | other campus: per site receivers
|
||
|
|
- [config-key] config: check shure :: shure.channels @ config.json:226-230; status_panel.py:335,566 | today: edit config.json, install.sh | int; default 1; channels 1..N read | other campus: per receiver
|
||
|
|
- [config-default] config: check shure :: shure.battery_err_bars @ status_panel.py:340 | today: not set; edit config.json, install.sh | int 0-5; default 1; bars <= this = red "<CH> BATT" | other campus: same
|
||
|
|
- [config-default] config: check shure :: shure.battery_warn_bars @ status_panel.py:342 | today: not set; edit config.json, install.sh | int 0-5; default 2; bars <= this = amber | other campus: same
|
||
|
|
- [config-key] config: check psm :: psm.conn + polled variables @ status_panel.py:355-366,569-571 | today: edit config.json, install.sh | Companion label (PSM_1..3); reads ch_N_name, ch_N_rf_mute every 3 s | other campus: per site
|
||
|
|
- [config-key] config: check psm :: psm.channels @ config.json:232-236; status_panel.py:362,570 | today: edit config.json, install.sh | int; default 1 | other campus: per unit
|
||
|
|
- [config-default] config: check psm :: psm.muted_is_error @ status_panel.py:361 | today: not set; edit config.json, install.sh | bool; default false (RF MUTE is amber); true = red | other campus: same
|
||
|
|
- [config-key] config: check tascam :: tascam.conn + polled variables @ status_panel.py:369-385,563-564 | today: edit config.json, install.sh | Companion label; reads variables error and caution every 1 s; no other fields; "no error"/"no caution" = OK, else text upper-cased to 14 chars | other campus: same
|
||
|
|
- [config-key] config: check ping :: ping.host @ config.json:143,184,202-203,221-222,227-237; status_panel.py:388-399,2277-2282 | today: edit config.json, install.sh | IP/hostname; the address pinged (every 3 s, 1 s timeout, /sbin/ping); when conn is set, Companion's own host setting for that connection wins and host is only the fallback; chk["host"] is read for the default message so a ping check with neither host nor name/msg crashes that check (CHECK BUG) | other campus: per site IPs
|
||
|
|
- [config-key] config: check ping :: ping.conn @ config.json:143,227-237; status_panel.py:388-391,1585-1590 | today: edit config.json, install.sh | optional Companion label; its "host" setting is read from Companion's db.sqlite every 60 s so an address changed in Companion needs no config change | other campus: same
|
||
|
|
- [config-key] config: check ping :: ping.name @ status_panel.py:397 | today: edit config.json, install.sh | string; default = host; fault text "<name> NO PING" | other campus: same
|
||
|
|
- [config-default] config: check ping :: ping.msg @ status_panel.py:397 | today: not set; edit config.json, install.sh | string; optional full fault text replacing "<name> NO PING" | other campus: same
|
||
|
|
- [config-default] config: check ping :: ping.failures @ status_panel.py:396 | today: not set; edit config.json, install.sh | int consecutive misses; default 2 (~6 s at the 3 s poll) | other campus: same
|
||
|
|
- [config-key] config: check launchd :: launchd.label @ config.json:210-212; status_panel.py:402-410,1477-1484 | today: edit config.json, install.sh | LaunchAgent label string (org.waterschurch.lobby-captions); required; `launchctl list` every 10 s: missing = "<name> NOT LOADED", loaded with no pid = "<name> STOPPED" | other campus: per site agents
|
||
|
|
- [config-key] config: check launchd :: launchd.name @ status_panel.py:405 | today: edit config.json, install.sh | string; default = label | other campus: same
|
||
|
|
- [config-key] config: check process :: process.match @ config.json:214; status_panel.py:413-417,1486-1489 | today: edit config.json, install.sh | `pgrep -f` pattern (regex against the full command line); required; polled every 10 s | other campus: per app path
|
||
|
|
- [config-key] config: check process :: process.name @ status_panel.py:416 | today: edit config.json, install.sh | string; default "PROCESS"; fault "<name> STOPPED" | other campus: same
|
||
|
|
- [config-key] config: check http :: http.url @ config.json:185-186,204,206,213,215; status_panel.py:420-423,1527-1541,2285-2292 | today: edit config.json, install.sh | URL string; required; HEAD request, 6 s timeout, TLS not verified; any HTTP answer (even 4xx/5xx) = up | other campus: per site
|
||
|
|
- [config-key] config: check http :: http.msg @ status_panel.py:422 | today: edit config.json, install.sh | string; default "<name> UNREACH" | other campus: same
|
||
|
|
- [config-key] config: check http :: http.name @ config.json:206; status_panel.py:422 | today: edit config.json, install.sh | string; default "WEB" | other campus: same
|
||
|
|
- [config-key] config: check http :: http.interval_seconds @ config.json:185,204,213,215; status_panel.py:2291,2313 | today: edit config.json, install.sh | seconds; default 30; the smallest value wins when the same URL appears twice; the http poller runs every 5 s so values below 5 behave as 5 | other campus: same
|
||
|
|
- [config-key] config: check disk :: disk.path @ config.json:216; status_panel.py:456-465,1490-1492 | today: edit config.json, install.sh | filesystem path; required; free GB read every 10 s; shows "<n>GB free" | other campus: same
|
||
|
|
- [config-key] config: check disk :: disk.warn_gb @ config.json:216; status_panel.py:463 | today: edit config.json, install.sh | number; default 20; below = amber "DISK nGB" | other campus: same
|
||
|
|
- [config-key] config: check disk :: disk.err_gb @ config.json:216; status_panel.py:461 | today: edit config.json, install.sh | number; default 5; below = red | other campus: same
|
||
|
|
- [config-key] config: check midi_peer :: midi_peer.session @ config.json:161-166; status_panel.py:476-478,995,1961 | today: edit config.json, install.sh | network MIDI session name as in Audio MIDI Setup ("NA Ingest", "NA Tracks"); required; missing session = red NO SESSION | other campus: per Mac session names
|
||
|
|
- [config-key] config: check midi_peer :: midi_peer.peer @ config.json:161-166; status_panel.py:479-487,995,1961 | today: edit config.json, install.sh | participant name as the session lists it ("Lighting PC"); required; state running|connected = OK, other = "MIDI <STATE>", absent = MIDI LOST | other campus: per site
|
||
|
|
- [config-key] config: check midi_peer :: midi_peer.host @ config.json:163-166; status_panel.py:471-473,1663-1746,1962-1966 | today: edit config.json, install.sh; the other Mac needs the ssh key authorised | optional hosts alias; the session is read on that Mac over one long-lived ssh running coremidi.py with /usr/bin/python3 (nothing installed there); no verdict if it has not reported for 12 s; NOT validated by load_config (a bad alias kills that stream thread) | other campus: per site Macs
|
||
|
|
- [config-key] config: check midi_peer :: midi_peer.address @ config.json:161-166; status_panel.py:996-999 | today: edit config.json, install.sh | "ip:port" or Bonjour "\tName\tlocal." form; optional fallback for the midi_reconnect fix when the peer was never seen; last-seen address wins | other campus: per site
|
||
|
|
- [config-default] config: check midi_peer :: midi_peer.debounce_seconds (implicit) @ status_panel.py:881-884 | today: not set | default 1 s for this type (a peer leaving is a clean event) | other campus: same
|
||
|
|
- [config-key] config: check pref :: pref.domain @ config.json:197; status_panel.py:448-453,1493-1496 | today: edit config.json, install.sh | macOS defaults domain string; required; `defaults read <domain> <key>` every 10 s on the ingest Mac | other campus: same app = same domain
|
||
|
|
- [config-key] config: check pref :: pref.key @ config.json:197; status_panel.py:450,1494 | today: edit config.json, install.sh | defaults key string; required | other campus: same
|
||
|
|
- [config-key] config: check pref :: pref.want @ config.json:197; status_panel.py:451 | today: edit config.json, install.sh | value compared as a string to what defaults prints ("0"); required; unreadable key = OK (no verdict) | other campus: same
|
||
|
|
- [config-key] config: check pref :: pref.msg @ config.json:197; status_panel.py:453 | today: edit config.json, install.sh | fault text; required (KeyError otherwise) | other campus: same
|
||
|
|
- [config-key] config: check spotify :: spotify.playlist @ config.json:173; status_panel.py:1619-1630,1597-1616 | today: edit config.json (TWICE: here and inside fixes.spotify_play.run), install.sh | "spotify:playlist:<id>" URI; required; only the FIRST spotify check's playlist is fetched (public embed page + anonymous token, hourly and on an unknown song); WRONG PLAYLIST when the current song is not in it (3 strangers in a row if only part of the list is known) | other campus: per site playlist; the UI must write both places (or the fix should read it from the check)
|
||
|
|
- [config-key] config: check spotify :: spotify.name @ config.json:173 | today: edit config.json | string; NOT read by any code today (documentation only); the fix label hardcodes "Christian EDM 2026" | other campus: per site
|
||
|
|
- [hardcoded] config: check spotify :: spotify hardcoded behaviour @ status_panel.py:426-445,1593-1594,1631-1645,156-158 | today: edit source | polled every 3 s via pgrep + osascript (never opens Spotify); CLOSED/NOT PLAYING red; refresh 3600 s; remembers last 3 tracks; needs Automation permission for Spotify on the ingest Mac | other campus: same | (need not be editable)
|
||
|
|
- [config-key] config: check mdns :: mdns.instance @ config.json:168-169; status_panel.py:490-493,1510-1518 | today: edit config.json, install.sh | Bonjour _apple-midi._udp instance name; required; browsed 3 s every 15 s; missing = "<name> GONE" | other campus: per site
|
||
|
|
- [config-key] config: check mdns :: mdns.name @ status_panel.py:492 | today: edit config.json, install.sh | string; default = instance | other campus: same
|
||
|
|
- [config-key] config: check midi_rx :: midi_rx.source @ config.json:170; status_panel.py:496-507,1652-1658 | today: edit config.json, install.sh | CoreMIDI source name on the ingest Mac ("Network NA Ingest Listen"); required; a coremidi.Listener is attached; grey OFF while not connected, else "<name> <age>" | other campus: per Mac source name
|
||
|
|
- [config-key] config: check midi_rx :: midi_rx.name @ status_panel.py:498 | today: edit config.json, install.sh | string; default "MIDI" | other campus: same
|
||
|
|
- [config-default] config: check midi_rx :: midi_rx.max_silence_seconds @ status_panel.py:504-506; README.md:185 | today: not set; edit config.json, install.sh | seconds; default none = informational only; set = amber "<name> SILENT" when no MIDI for that long, only while service mode is on | other campus: same
|
||
|
|
- [config-key] config: check remote :: remote.host @ config.json:180-189; status_panel.py:523-531,1782-1799,2257 | today: edit config.json, install.sh | hosts alias; required; validated; all remote cmds for one host are batched into one ssh every 10 s | other campus: per site
|
||
|
|
- [config-key] config: check remote :: remote.cmd @ config.json:180-189; status_panel.py:524,1772-1774 | today: edit config.json, install.sh | shell command run on that machine; required; exit 0 = OK, non-zero = fault, unreachable = no verdict; duplicates per host collapsed | other campus: per site
|
||
|
|
- [config-key] config: check remote :: remote.msg @ status_panel.py:530 | today: edit config.json, install.sh | fault text; required (KeyError otherwise) | other campus: same
|
||
|
|
- [config-key] config: check artnet :: artnet.source @ config.json:176; status_panel.py:510-520,2184-2208 | today: edit config.json, install.sh | IP string of the Art-Net sender; required; passive listener on UDP 6454 (SO_REUSEPORT), started only when an artnet check exists | other campus: per site lighting PC IP
|
||
|
|
- [config-key] config: check artnet :: artnet.max_silence_seconds @ config.json:176; status_panel.py:512 | today: edit config.json, install.sh | seconds; default 5 | other campus: same
|
||
|
|
- [config-default] config: check artnet :: artnet.msg @ status_panel.py:519 | today: not set; edit config.json, install.sh | string; default "SILENT" (tile label is prefixed); a custom msg is shown as-is | other campus: same
|
||
|
|
- [config-key] config: check atem :: atem check .part @ config.json:195-196; status_panel.py:2170-2178 | today: edit config.json, install.sh | "audio"|"camera"; required; no verdict unless atem_watch.js reported within 30 s and is connected | other campus: same
|
||
|
|
- [config-key] config: check atem :: atem check .msg @ config.json:195-196; status_panel.py:2177 | today: edit config.json, install.sh | fault text; required (KeyError otherwise); info shows the first 3 differences | other campus: same
|
||
|
|
- [config-key] config: atem section :: atem (section presence) @ config.json:91-96; status_panel.py:2320-2328 | today: edit config.json, install.sh | object; the watcher starts only when the section exists AND at least one atem check exists; if node/library are not found the ATEM checks are silently off (warning in log) | other campus: omit at a site without an ATEM
|
||
|
|
- [config-key] config: atem section :: atem.host @ config.json:92; status_panel.py:2120 | today: edit config.json, install.sh | switcher IP; required | other campus: per site
|
||
|
|
- [config-key] config: atem section :: atem.node @ config.json:93; status_panel.py:2108,2089-2095 | today: edit config.json, install.sh | glob pattern to Companion's bundled node binary; required; newest version match wins; ~ expanded | other campus: same unless Companion is installed elsewhere
|
||
|
|
- [config-key] config: atem section :: atem.library @ config.json:94; status_panel.py:2108 | today: edit config.json, install.sh | glob pattern to the atem-connection module inside Companion's bmd-atem module; required; newest wins | other campus: same
|
||
|
|
- [config-key] config: atem section :: atem.reference @ config.json:95; status_panel.py:2111-2115,2061-2086; install.sh:28 | today: copy a new ATEM Software Control .xml over atem-reference.xml, zsh install.sh | path to the restore .xml; relative paths are relative to the script folder, ~ expanded; converted to atem-reference.json in the data dir at start; which settings are compared is hardcoded (MIX_OPTIONS/CCU_PARAMS :2042-2058) | other campus: per site restore file (today from Google Drive Backup/NA/ATEM)
|
||
|
|
- [config-key] config: auto_fix :: auto_fix (section) @ config.json:98-105; status_panel.py:772-775,1154-1246 | today: edit config.json, install.sh | object; absent or empty = auto-fix completely off; runs every 5 s while inside a window AND service mode is on | other campus: per site
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.windows @ config.json:99; status_panel.py:1164-1174 | today: edit config.json, install.sh | list of {days,start,end} like service_windows; default []; today Sunday 06:30-13:30 | other campus: per site service times
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.after_seconds @ config.json:100; status_panel.py:1206 | today: edit config.json, install.sh | seconds a red fault must have lasted; default 20 | other campus: same
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.max_tries @ config.json:100; status_panel.py:1211-1218,1234 | today: edit config.json, install.sh | int; default 2; then "gave up" in the auto-fix log until the fault is forgotten | other campus: same
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.retry_seconds @ config.json:100; status_panel.py:1219 | today: edit config.json, install.sh | seconds between tries; default 90 (plus the global 60 s fix cooldown) | other campus: same
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.pause_after_network_seconds @ config.json:100; status_panel.py:1178-1186 | today: edit config.json, install.sh | seconds; default 60; no auto-fixes while link/gateway are down or a burst is on/just cleared | other campus: same
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.restart_connections @ config.json:101; status_panel.py:1207 | today: edit config.json, install.sh | bool; default false; true = plain Companion reconnects are also done automatically | other campus: same
|
||
|
|
- [config-key] config: auto_fix :: auto_fix.fixes @ config.json:102-104; status_panel.py:1187,1207,2261-2265 | today: edit config.json, install.sh | list of fix ids that auto-fix may run ("gentle"); validated to exist and to not contain pkill/taskkill/killall in run unless restart_ok; everything else stays a hold | other campus: per site
|
||
|
|
- [config-default] config: auto_fix :: auto_fix.forget_seconds @ status_panel.py:1240-1245 | today: not set; edit config.json, install.sh | seconds; default 600; a fault's try count resets once it has been gone this long | other campus: same
|
||
|
|
- [config-default] config: auto_fix :: auto_fix.log_dir @ status_panel.py:775,625-686 | today: not set; edit config.json, install.sh | directory, ~ expanded; default "~/Desktop/Auto-Fix Logs"; one "YYYY-MM-DD Day Auto-Fix.log" per day, deleted after a calendar month; header text hardcodes "NA Ingest ... Sundays 06:30-13:30" (:680-682) | other campus: per site; header wording needs a site-name key
|
||
|
|
- [config-key] config: restart_page :: restart_page (section) @ config.json:107-124; status_panel.py:771; make_page.py:274-277,281-288,301-304; push_page.py:179 | today: edit config.json, make_page.py, push_page.py --which restart, install.sh | optional object; when present make_page also builds restart-page.companionconfig and places a RESTART PAGE jump key on the status page | other campus: per site
|
||
|
|
- [config-key] config: restart_page :: restart_page.page @ config.json:108; make_page.py:277,288; push_page.py:179 | today: edit config.json, make_page.py, push_page.py --which restart | int Companion page number (20); required when the section exists | other campus: per site
|
||
|
|
- [config-key] config: restart_page :: restart_page.page_name @ config.json:108; make_page.py:288; push_page.py:179,188 | today: edit config.json, make_page.py, push_page.py --which restart | string with literal \n ("20\nRestart"); required; push_page matches on it | other campus: per site
|
||
|
|
- [config-key] config: restart_page :: restart_page.jump_pos @ config.json:108; make_page.py:276 | today: edit config.json, make_page.py, push_page.py | [row,col] on the STATUS page for the grey "RESTART PAGE" key; required; must not collide with a tile pos | other campus: per layout
|
||
|
|
- [config-key] config: restart_page :: restart_page.back_pos @ config.json:108; make_page.py:284 | today: edit config.json, make_page.py, push_page.py --which restart | [row,col] on the RESTART page for the "STATUS PAGE" key; required; must not collide with a restart key pos | other campus: per layout
|
||
|
|
- [config-key] config: restart_page :: restart_page.keys[].id @ config.json:110-122; status_panel.py:771,1260,2266-2268; make_page.py:137,144-145 | today: edit config.json, make_page.py, push_page.py --which restart, install.sh | string; required; must not equal a tile id (validated); same identifier rules as tile ids (jsonpath); command "force <id>" | other campus: same
|
||
|
|
- [config-key] config: restart_page :: restart_page.keys[].label @ config.json:110-122; status_panel.py:1372-1376; make_page.py:134 | today: edit config.json, make_page.py, push_page.py --which restart, install.sh | key text; required; shows "<label>\nHOLD 2s" / "HOLD TO FIX" / RESTARTING / DONE / FAILED | other campus: same
|
||
|
|
- [config-key] config: restart_page :: restart_page.keys[].pos @ config.json:110-122; make_page.py:287 | today: edit config.json, make_page.py, push_page.py --which restart | [row,col] on the restart page; required; collision raises | other campus: per layout
|
||
|
|
- [config-key] config: restart_page :: restart_page.keys[].fix @ config.json:110-122; status_panel.py:1264,1369,2269-2270; make_page.py:141 | today: edit config.json, make_page.py, push_page.py --which restart, install.sh | fix id; required; validated to exist; runs whatever the status says (shares the 60 s guard with holds) | other campus: per site
|
||
|
|
- [config-key] config: restart_page :: restart_page.keys[].watch @ config.json:115-116,120,122; status_panel.py:1265-1270,1369-1374,2271-2273 | today: edit config.json, install.sh | list of fix ids or "conn:<Companion label>"; default []; the key flashes HOLD TO FIX when its fix or any watched fix/connection is failing; a watched fix that ran <60 s ago makes the key say "STARTING WAIT 1 MIN"; fix ids validated, conn labels not | other campus: per site
|
||
|
|
- [hardcoded] config: restart_page :: make_page "options/steps/style" are NOT restart-key config @ make_page.py:207-232 (nav_key), nav_templates.json | today: n/a | key["style"], key["steps"], key["options"] in make_page.py are read from nav_templates.json (Companion's own pageup/pagenum/pagedown exports), not from restart_page.keys; restart keys accept only id, label, pos, fix, watch | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: page build :: HOLD_MS = 2000 @ make_page.py:36,144-146,181-182 | today: edit make_page.py, make_page.py, push_page.py | hold time in ms for every status tile and restart key | other campus: same; candidate config key
|
||
|
|
- [hardcoded] hardcoded: page build :: STALE_SECONDS = 15 and PURPLE = 0x6A1B9A @ make_page.py:34-35,53,61-65,209-212 | today: edit make_page.py | heartbeat age after which every key turns purple WATCHDOG DOWN | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: page build :: GRID = columns 0..8, rows 0..5 @ make_page.py:33 | today: edit make_page.py | page grid size written into the export; a site with a different surface needs it changed | other campus: per surface; candidate config key
|
||
|
|
- [hardcoded] hardcoded: page build :: NAV_LOCATIONS pageup (0,0) pagenum (1,0) pagedown (2,0) @ make_page.py:195,241-244; nav_keys.py:24,113-114 | today: edit make_page.py | column 0 rows 0-2 are always the nav keys; tiles cannot use them | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: page build :: EXPORT_VERSION 12 / COMPANION_BUILD 5.0.7 @ make_page.py:31-32,257-259 | today: edit make_page.py when Companion's export format changes | export format stamps; push_page/nav_keys written against Companion 5.0.7's tRPC API | other campus: same Companion version needed per site | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: page build :: push_page.py / nav_keys.py --host na-ingest.local --port 8000 @ push_page.py:172-173; nav_keys.py:84-85 | today: pass --host/--port on the command line | CLI defaults; these scripts read config.json only for page numbers/names and ignore companion.host/port | other campus: another site must pass --host; should read companion.host
|
||
|
|
- [hardcoded] hardcoded: page build :: "on NA Ingest" wording in key notes and docstrings @ make_page.py:141,188; status_panel.py:2,427,680-682,2431,2438 | today: edit source | site name appears in Companion button notes, auto-fix log header and webhook text | other campus: needs a site_name config key
|
||
|
|
- [hardcoded] hardcoded: watchdog timing :: poller intervals @ status_panel.py:2303-2316 | today: edit source | connections 1 s, fast variables 1 s, slow variables 3 s, Companion db hosts 60 s, spotify 3 s, pings 3 s, local MIDI 0.5 s, system (launchd/process/disk/pref) 10 s, Bonjour 15 s, http 5 s, remote ssh 10 s, dante-map 30 s; redraw 0.5 s (:2400), command poll 0.25 s (:2440) | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog timing :: fix cooldown 60 s @ status_panel.py:1041,1074,1256,1219 | today: edit source | the same fix (per deck / per MIDI peer) never re-runs within 60 s; key says JUST TRIED WAIT 1 MIN | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog timing :: HOLD_MAX_AGE 15 s @ status_panel.py:2345,2365-2370 | today: edit source | a hold/force stamped more than 15 s ago (queued while the watchdog was down) is dropped | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog timing :: freshness limits @ status_panel.py:181 (conns 10 s), 472 (remote MIDI 12 s), 2173 (ATEM 30 s), 2387 (2.5 s start grace), 2437 (webhook after 30 s) | today: edit source | NO DATA when Companion data is older than 10 s; remote MIDI no verdict after 12 s; ATEM no verdict after 30 s | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: COLORS table / display levels @ status_panel.py:41-61,1299-1310 | today: edit source | ok green, warn amber, notice flashing amber, quiet dark red (fault while ALARMS off), ack dark red, err flashing red, off/idle grey, service blue, fixing blue, failed orange | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: RESTARTABLE = conn, hyperdeck, shure, psm, tascam @ status_panel.py:542,932,1005; make_page.py:29,167 | today: edit source | check types whose Companion connection a hold restarts when they have no fix; also decides whether make_page gives the key a hold action | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: ssh options @ status_panel.py:1748-1753,1707 | today: edit source | /usr/bin/ssh -i <ssh_key> BatchMode=yes ConnectTimeout=5 IdentitiesOnly=yes StrictHostKeyChecking=accept-new ControlMaster=auto ControlPath=/tmp/status-panel-ssh-%C ControlPersist=120; remote python is /usr/bin/python3 (:1708,1741,1963) | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: ports: WoL 9, Art-Net 6454, HyperDeck 9993, telnet 23 @ status_panel.py:1759,2184,1802; netgear.py:38 | today: edit source | hyperdeck_probe (9993) is defined but only used by tests, not by any fix path | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: ATEM compared settings (MIX_OPTIONS, CCU_PARAMS) @ status_panel.py:2042-2058 | today: edit source | Fairlight mixOption + faderGain per source; camera iris, white balance, exposure, detail, gain, ND, lift/gamma/gain/offset, contrast, luma mix, colour | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: text fitting LINE_CAPACITY 145 / sizes 30..12 @ status_panel.py:1331-1356 | today: edit source | key text size chosen per key so words never break; measured on Companion web buttons | other campus: same | (need not be editable)
|
||
|
|
- [hardcoded] hardcoded: watchdog :: CLI: --config, --data-dir, --log, --once, --dry-run @ status_panel.py:2479-2497; install.sh:33-39 | today: LaunchAgent passes --data-dir "$HOME/Library/Application Support/status-panel"; --config defaults to config.json beside the script; --log ~/Library/Logs/status-panel.log (1 MB x3) | the running config is the COPY in App Support, not the repo file; a UI must edit that copy (or re-run install.sh) | other campus: same
|
||
|
|
- [runtime-data] runtime-data :: data dir files: service-mode.json, dante-map.json, atem-reference.json, config.json.bak-* @ status_panel.py:2384-2385,1839,2107; install.sh:24-26 | today: written by the watchdog / install.sh | ALARMS override + last schedule; Dante name->ip/mac/switch/port/poe/seen; converted ATEM restore; timestamped config backups on each install | other campus: same
|
||
|
|
- [companion-side] companion-side :: Companion connection labels referenced by checks @ config.json tiles (HyperDeck_1-6, tascam, x32, audinate-dantecontroller, lighting-midi, Propresenter-API, ableton, BibleTV, ATEM, OBS-Youtube, RESI_Decoder, resi-studio-cues, VX1000, UHDJr, arena, Axient_1/2, ULXD-4, PSM_1-3) | today: rename in Companion AND in config.json | exact label match; a renamed connection shows NOT IN COMPANION; the UI should read /api/connections to offer the live list and flag mismatches | other campus: per site
|
||
|
|
- [companion-side] companion-side :: custom variables sp_state, sp_hb, sp_cmd must be created by hand @ status_panel.py:2421-2427; README.md:128 | today: Companion web UI once | names come from variables.*; watchdog only warns when missing | other campus: per Companion
|
||
|
|
- [secret] secret :: Netgear switch login in the login keychain (service "netgear-status-panel") @ netgear.py:4-10,22,25-35 | today: security add-generic-password -s netgear-status-panel -a <user> -w (in Terminal on the ingest Mac, logged-in session) | account = username, password never printed; needed for dante_switches survey and PoE cycle; the UI should only show present/absent and never the value | other campus: per site switches
|
||
|
|
- [external-setup] external-setup referenced from config strings :: things fixes.run strings depend on @ config.json:48-50 (/usr/local/sbin/status-panel-dvs-start via sudo -n), 53-55,67 (LaunchAgents org.waterschurch.*), 57-65 (schtasks \StatusPanel\Start BibleApp/OBS/Arena/Vista/rtpMIDI), 69,188-189 (~/Library/Application Support/status-panel/solo-mode.json on studiob), 76 (Spotify Automation permission) | today: remote-access/mac-dvs-helper.sh, windows-setup.ps1, install-solo-mode.sh; by hand | each is a plain string inside run; nothing verifies it exists until the fix fails | other campus: per machine; the UI should show per host which helpers are installed
|
||
|
|
- [workflow-step] workflow-step :: install.sh copies status_panel.py coremidi.py netgear.py config.json atem_watch.js atem-reference.xml to ~/Library/Application Support/status-panel and restarts LaunchAgent org.waterschurch.status-panel @ install.sh:9-11,22-28,41-60 | today: zsh install.sh on the ingest Mac after any config change | validates config.json is JSON only (no load_config); backs up the old config; atem_state.js/nav_templates.json not needed at runtime | other campus: same per ingest Mac
|
||
|
|
|
||
|
|
### Lens: WHAT RUNS WHERE: every machine the status panel touches, what is installed/configured on each, how it got there, how to tell it is alive, and which panel keys depend on it
|
||
|
|
- [workflow-step] Your MacBook (dev) :: Project folder (source of truth) + git @ MacBook: /Users/christian/Documents/Status Indicators (git, branch main) | today: edit files here, git commit, git push | Verify: git status clean; git log. Panel: nothing at runtime (NA Ingest runs copies) | other campus: one repo per site, or one repo with per-site config files; code must stay shared | (need not be editable)
|
||
|
|
- [external-setup] Your MacBook (dev) :: Gitea remote christian/status-indicators (private) @ MacBook: origin http://chronicles-ab.waterschurch.org:3000/christian/status-indicators.git | today: git push with credential helper reading keychain item gitea-mcp (see .claude/settings.local.json) | Verify: git remote -v; git ls-remote origin | other campus: same repo; keep private (guideline 13) | (need not be editable)
|
||
|
|
- [external-setup] Your MacBook (dev) :: SSH alias checklist-ingest -> NA Ingest @ MacBook: ~/.ssh/config Host checklist-ingest (HostName 10.1.1.1, User Studio, IdentityFile ~/.ssh/id_ed25519_checklist_ingest) | today: edited by hand in ~/.ssh/config; key authorized on NA Ingest by hand | Verify: ssh -o BatchMode=yes checklist-ingest 'hostname'. Used by scp/install deploy and all remote checks from the MacBook | other campus: one alias per site Ingest Mac (checklist-<site>) | (need not be editable)
|
||
|
|
- [workflow-step] Your MacBook (dev) :: Memory files (project history + guidelines) @ MacBook: ~/.claude/projects/-Users-christian-Documents-Status-Indicators/memory/companion-status-page.md and status-panel-guidelines.md | today: written by Claude sessions | Verify: files exist. Panel: none | other campus: n/a | (need not be editable)
|
||
|
|
- [external-setup] NA Ingest: watchdog :: LaunchAgent org.waterschurch.status-panel (the watchdog) @ NA Ingest (Studio@10.1.1.1): ~/Library/LaunchAgents/org.waterschurch.status-panel.plist; runs /usr/bin/python3 '~/Library/Application Support/status-panel/status_panel.py' --data-dir <that folder>; RunAtLoad, KeepAlive, ThrottleInterval 10 | today: install.sh:30-58 writes the plist and bootout/bootstraps gui/<uid>; 'zsh install.sh --remove' stops it | Verify: launchctl list | grep status-panel (PID shown, e.g. 99852); curl 127.0.0.1:8000/api/custom-variable/sp_hb/value within 15 s of now; page turns PURPLE 'WATCHDOG DOWN' when it stops. Panel: everything | other campus: same install.sh per site; label could carry the site name
|
||
|
|
- [workflow-step] NA Ingest: watchdog :: Install staging folder @ NA Ingest: ~/status-panel-install/ (status_panel.py, coremidi.py, netgear.py, atem_watch.js, config.json, atem-reference.xml, install.sh) | today: scp from the MacBook (README 'Changing things'), then ssh checklist-ingest 'zsh ~/status-panel-install/install.sh' | Verify: ls ~/status-panel-install; cmp with App Support copies | other campus: same path per site | (need not be editable)
|
||
|
|
- [external-setup] NA Ingest: watchdog :: Data dir ~/Library/Application Support/status-panel @ NA Ingest: that folder (install.sh:11 DEST; App Support because launchd python cannot read ~/Documents) | today: install.sh:23-28 copies status_panel.py, coremidi.py, netgear.py, config.json, atem_watch.js, atem-reference.xml into it | Verify: ls -la the folder; mtime of config.json matches the deployed one | other campus: same
|
||
|
|
- [external-setup] NA Ingest: watchdog :: /usr/bin/python3 3.9.6 (macOS Xcode python, stdlib only) @ NA Ingest: /usr/bin/python3 (Xcode Python3.framework 3.9); macOS 26.5.1 | today: comes with Xcode / Command Line Tools; nothing installed (R9) | Verify: /usr/bin/python3 --version. Panel: whole watchdog; telnetlib (netgear.py) needs 3.9-era stdlib | other campus: every Ingest Mac needs Xcode CLT python3; telnetlib is removed in newer pythons
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Watchdog log (rotating) @ NA Ingest: ~/Library/Logs/status-panel.log (1 MB x 3, status_panel.py:2485,2491) and ~/Library/Logs/status-panel.err.log (launchd stderr, install.sh:46) | today: written by the watchdog; every fault/clear/HOLD/FIX line | Verify: tail -f ~/Library/Logs/status-panel.log; err.log should stay 0 bytes | other campus: same
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Auto-Fix daily logs @ NA Ingest: ~/Desktop/Auto-Fix Logs/<YYYY-MM-DD Weekday> Auto-Fix.log (AutoLog status_panel.py:625-686; dir from auto_fix.log_dir default ~/Desktop/Auto-Fix Logs) | today: written by auto_fix(); files deleted a calendar month after their date | Verify: ls '~/Desktop/Auto-Fix Logs' (today: 2026-10-11 Sunday, 2026-10-13 Tuesday). Double-click opens Console | other campus: same; folder name configurable
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: service-mode.json (ALARMS override) @ NA Ingest: ~/Library/Application Support/status-panel/service-mode.json ({override, last_sched}; ServiceMode status_panel.py:696-739) | today: written when ALARMS key is pressed or a window edge passes | Verify: cat the file (now {"override": null, "last_sched": true}). Panel: ALARMS key, auto-fix on/off | other campus: same
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: dante-map.json (self-updating Dante device map) @ NA Ingest: ~/Library/Application Support/status-panel/dante-map.json (poll_dante_map status_panel.py:1869-1906; every 30 s until first success then dante_map_seconds=600) | today: built automatically from Companion Dante vars + arp -an + Netgear MAC/PoE tables | Verify: python3 -c to print it (19 devices today; PoE: STUDIO-B-MON 0/15, SOLO-MON 0/14, TB 0/16, TB-MON 0/17 on 10.66.1.102); log line 'dante map: N devices'. Panel: DANTE hold (dante-auto) | other campus: automatic per site
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: atem-reference.json (derived from the restore XML) @ NA Ingest: ~/Library/Application Support/status-panel/atem-reference.json (AtemWatcher.__init__ status_panel.py:2107-2115 writes it on every start from atem-reference.xml) | today: regenerated at watchdog start; source XML copied by install.sh:28 | Verify: file mtime == last watchdog start; ATEM key green. Panel: ATEM AUDIO/CAMERA WRONG | other campus: each site has its own restore XML
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: config.json backups @ NA Ingest: ~/Library/Application Support/status-panel/config.json.bak-YYYYmmdd-HHMMSS (install.sh:24-26; 46 of them today) | today: install.sh makes one whenever the config differs | Verify: ls config.json.bak-*. Useful as the history/rollback source the UI needs (R8) | other campus: same
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: SSH multiplex sockets @ NA Ingest: /tmp/status-panel-ssh-%C (ssh_cmd status_panel.py:1748-1753: ControlMaster=auto, ControlPersist=120, BatchMode, ConnectTimeout=5, IdentitiesOnly, StrictHostKeyChecking=accept-new) | today: created by ssh on first use per host | Verify: ls /tmp/status-panel-ssh-*; pgrep -lf 'ssh.*id_status_panel'. Panel: all remote checks/fixes | other campus: same | (need not be editable)
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Long-lived MIDI session streams to NA Tracks and ProPresenter Mac @ NA Ingest: one ssh per host (stream_remote_midi status_panel.py:1700-1734) running /usr/bin/python3 -u - with coremidi.py piped over stdin; nothing installed on the far Mac | today: started by start_pollers for every midi_peer check with a 'host' | Verify: pgrep -lf 'ServerAliveInterval=2' on NA Ingest (one per host, e.g. PID 6558); MIDI key shows no 'NO SESSION'. Panel: MIDI (FX LIGHTS, TRK LIVEBOX, TRK STUDIO B, PROP LIGHTS) | other campus: any Mac with Remote Login + /usr/bin/python3
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: ATEM watcher subprocess (atem_watch.js on Companion's node) @ NA Ingest: <Companion 5.0.7.app>/Contents/Resources/node-runtimes/node22/bin/node + ~/Library/Application Support/companion/modules/bmd-atem-3.19.1/node_modules/atem-connection (config atem.node / atem.library globs; newest() status_panel.py:2089; AtemWatcher 2098-2164) | today: globs resolve to the newest Companion app and newest bmd-atem module; restarts itself every 5 s if it dies | Verify: pgrep -lf atem_watch.js; log 'ATEM watcher stopped' absent; ATEM key green. Panel: ATEM AUDIO/CAMERA; atem_audio/atem_camera fixes | other campus: depends on the Companion app version and bmd-atem module being installed there
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Art-Net listener UDP 6454 @ NA Ingest: watchdog socket on 0.0.0.0:6454 with SO_REUSEPORT (start_artnet_listener status_panel.py:2184-2208) | today: started when any 'artnet' check exists | Verify: lsof -nP -iUDP:6454; log 'Art-Net listener could not start' absent. Panel: VISTA (SILENT) | other campus: the lighting console's Art-Net must reach the Ingest Mac's subnet
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Bonjour browse of _apple-midi._udp @ NA Ingest: /usr/bin/dns-sd -B _apple-midi._udp local. every 15 s for 3 s (poll_mdns status_panel.py:1510) | today: built in | Verify: dns-sd -B _apple-midi._udp local. lists 'Lighting PC' and 'NA Tracks'. Panel: MIDI (LIGHT PC MIDI GONE, TRACKS MIDI GONE) | other campus: instance names differ per site (config mdns.instance)
|
||
|
|
- [external-setup] NA Ingest: watchdog :: Local CoreMIDI session read + 'NA Ingest Listen' session (optional) @ NA Ingest: coremidi.py via ctypes reads the network driver's apple.midirtp.session; session 'NA Ingest' (peers Lighting PC, SuperRack-LiveBox); optional 'NA Ingest Listen' session created in Audio MIDI Setup (README 'Optional') | today: sessions created/connected by hand in Audio MIDI Setup > MIDI Studio > Network | Verify: python3 -c 'import coremidi; print(coremidi.sessions())' in the data dir. Panel: MIDI (LIGHT PC, SUPERRACK), TRACKS IN line | other campus: session and peer names per site
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Local shell probes used by checks @ NA Ingest: /sbin/ping, /sbin/ifconfig en0, /bin/launchctl list, /usr/bin/pgrep, /usr/bin/defaults read, /usr/sbin/arp -an, shutil.disk_usage (poll_pings 1453, poll_system 1475, arp_table 1855) | today: built in | Verify: python3 status_panel.py --once prints every tile. Panel: NET, INGEST, ATEM SW MIDI, DANTE map | other campus: interface name (network.interface) and gateway per site | (need not be editable)
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Spotify control via osascript @ NA Ingest: /usr/bin/osascript 'tell application "Spotify"' every 3 s (poll_spotify status_panel.py:1619-1645, SPOTIFY_STATE 1593) + playlist list from open.spotify.com/embed and spclient.wg.spotify.com (playlist_tracks 1597) | today: built in; playlist URI in config tiles.spotify.checks[0].playlist and fixes.spotify_play.run (hardcoded twice) | Verify: SPOTIFY key green 'PLAYING'; log 'Spotify playlist list' warnings absent. Panel: SPOTIFY, rs_spotify | other campus: playlist URI per site; needs internet for the song list
|
||
|
|
- [runtime-data] NA Ingest: watchdog :: Read-only read of Companion's settings database @ NA Ingest: ~/Library/Application Support/companion/v5.0/db.sqlite opened mode=ro every 60 s (companion_db_path 1552, companion_conn_hosts 1563; table instances) | today: built in; override with config companion.db | Verify: log 'could not read connection addresses' absent. Panel: Shure/Tascam/LED pings and HyperDeck/Tascam hung-vs-off verdicts use the address set on the Companion connection | other campus: path follows the newest vN.N folder automatically | (need not be editable)
|
||
|
|
- [external-setup] NA Ingest: Companion :: Companion 5.0.7 (login item) @ NA Ingest: /Applications/Companion 5.0.7.app (also 5.0.3/5.0.4/5.0.5 and Companion.app present); HTTP API 127.0.0.1:8000; web UI http://na-ingest.local:8000 | today: installed by hand; macOS login item 'Companion' | Verify: curl -s 127.0.0.1:8000/api/connections | head -c 100; pgrep -lf 'Companion 5.0.7'. Panel: all keys; watchdog logs 'Companion unreachable' and posts alert_webhook after 30 s | other campus: version pinned in make_page.py (EXPORT_VERSION 12, COMPANION_BUILD 5.0.7+9763); old app copies could be deleted
|
||
|
|
- [external-setup] NA Ingest: Companion :: Custom variables sp_state, sp_hb, sp_cmd @ NA Ingest Companion: Variables > Custom Variables (names from config variables.state/heartbeat/command) | today: created BY HAND (README 'One-time Companion setup'); the API cannot create them (POST to a missing one -> 404) | Verify: curl -s -o /dev/null -w '%{http_code}' 127.0.0.1:8000/api/custom-variable/sp_hb/value -> 200 (all three 200 today). Panel: everything | other campus: create the three by hand on each site's Companion
|
||
|
|
- [external-setup] NA Ingest: Companion :: Custom variable flash_tick + trigger flash_tick_500 (blink clock) @ NA Ingest Companion: custom var flash_tick, trigger 'flash_tick_500' (controls table id trigger:324fEl4_yJyr6Uu71jvId, enabled) | today: pre-existing trigger; must stay enabled (README step 3) | Verify: custom-variable/flash_tick/value -> 200 and toggles 0/1; trigger enabled in Triggers page. Panel: blinking of every key and nav key | other campus: recreate the trigger on each site (not exported by make_page.py)
|
||
|
|
- [external-setup] NA Ingest: Companion :: Page 19 'Status' (8x4 keys) @ NA Ingest Companion page 19 (config page, page_name); built by make_page.py -> status-page.companionconfig; imported by push_page.py (tRPC importSinglePage) or by hand | today: python3 make_page.py; python3 push_page.py (refuses unless page empty or already the status page) | Verify: http://na-ingest.local:8000/tablet?pages=19&cols=8&rows=4; page_export via /int/export/page/19. Panel: the whole status page | other campus: page number per site in config
|
||
|
|
- [external-setup] NA Ingest: Companion :: Page 20 'Restart' @ NA Ingest Companion page 20 (config restart_page.page); restart-page.companionconfig | today: python3 make_page.py; python3 push_page.py --which restart | Verify: tablet view pages=20. Panel: restart keys rs_* | other campus: page number per site
|
||
|
|
- [external-setup] NA Ingest: Companion :: Coloured page-number nav key on all other pages (97 pages) @ NA Ingest Companion: location 1/0 on every page replaced by a copy of page 19's converted pagenum key; record in repo nav_locations.json; templates nav_templates.json; marker 'STATUS nav key' | today: python3 nav_keys.py (tRPC controls.copyControl); --revert resets; re-run after adding pages (guideline 9) | Verify: nav_keys.py --dry-run lists nothing to change; cat nav_locations.json. Panel: ALL colour visible from every page; tap -> page nav_tap_page, hold nav_hold_ms -> page 19 | other campus: run nav_keys.py on each site; nav_locations.json is per site
|
||
|
|
- [external-setup] NA Ingest: Companion :: Tascam quiet module 1.3.1-quiet @ NA Ingest: ~/Library/Application Support/companion/modules/tascam-da-6400-1.3.1-quiet (built by tascam-quiet/make_quiet_tascam.py from tascam-da-6400-1.3.0; tgz imported under Modules > Import module package; connection 'tascam' set to that version) | today: by hand in the Companion UI | Verify: ls the modules folder; Connections > tascam shows 1.3.1-quiet. Panel: TASCAM key (log flood otherwise) | other campus: import the tgz on each site that has a DA-6400
|
||
|
|
- [external-setup] NA Ingest: Companion :: Companion module folders used by the panel @ NA Ingest: ~/Library/Application Support/companion/modules/ (bmd-atem-3.19.1 used by atem_watch.js; bmd-hyperdeck-3.2.0, shure-wireless-2.3.1, shure-psm1000-2.0.3, audinate-dantecontroller-2.0.3-heartbeat-auto, novastar-controller-2.6.4, resi-decoders-2.0.0, resi-studio-cues-0.1.5, obs-studio-3.15.3, resolume-arena-3.12.0, generic-midi-1.4.0, ableton-osc-2.0.0, renewedvision-propresenter-api-1.2.0-rc4 etc.) | today: Companion module store / manual imports | Verify: ls that folder; each connection's version in the UI. Panel: all conn/variable checks | other campus: module set differs per site
|
||
|
|
- [external-setup] NA Ingest: Companion :: Companion Satellite (login item) @ NA Ingest: ~/Applications/Companion Satellite.app (running, PID 874) | today: installed by hand; login item | Verify: pgrep -lf 'Companion Satellite'. Panel: not checked today; surfaces it feeds are unknown | other campus: not determined
|
||
|
|
- [external-setup] NA Ingest: Companion :: Stream Deck surfaces (XL; MK.2 and Mini show top-left corner) @ NA Ingest Companion: Surfaces page; db tables surfaces/surface_groups | today: plugged in / configured in Companion UI (surface 'use last page' setting matters for the nav key, memory note) | Verify: Companion > Surfaces lists them (not read in this audit). Panel: which physical keys show pages 19/20 | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: HyperDeck_1..HyperDeck_6 (bmd-hyperdeck) + tcp-HyperDeck-1..6 (generic-tcp-udp) @ NA Ingest Companion connections; deck IPs on each connection (watchdog reads var 'ip' / db); control port 9993 probed by hyperdeck_probe status_panel.py:1802 | today: Companion UI; config tiles hd1..hd6 (HD2/HD4 optional:true) | Verify: /api/connections shows all 6 'good'; HD keys green with record time. Panel: HD1-6, REC group | other campus: which decks exist and which are optional is config; tcp-HyperDeck-n connections are separate (purpose not determined)
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: tascam (tascam-da-6400 1.3.1-quiet) -> DA-6400 10.1.11.74 @ NA Ingest Companion connection 'tascam'; ping 10.1.11.74 (config fallback host) | today: Companion UI; config tiles.tascam | Verify: connection good; ping 10.1.11.74. Panel: TASCAM (HUNG - POWER CYCLE IT / NO NETWORK), rs_tascam | other campus: address per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: x32 (behringer-x32) [m32 connection exists but OFF] @ NA Ingest Companion connection 'x32' | today: Companion UI | Verify: connection good. Panel: X32, AUDIO group | other campus: console model/label per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: ATEM (bmd-atem) -> switcher 10.1.10.2 @ NA Ingest Companion connection 'ATEM'; config atem.host 10.1.10.2 | today: Companion UI; config atem | Verify: connection good; atem_watch reports connected. Panel: ATEM, VIDEO group | other campus: switcher IP per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: audinate-dantecontroller (module 2.0.3-heartbeat-auto) -> 19 Dante devices @ NA Ingest Companion connection 'audinate-dantecontroller'; vars devices, <name>_ip; config tiles.dante.devices (19 names -> short labels) | today: Companion UI; config dante check 'devices' map and 'fix' map | Verify: /api/variable/audinate-dantecontroller/devices/value lists 19. Panel: DANTE (19/19, X GONE), AUDIO group | other campus: device list per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: Axient_1 10.1.1.101, Axient_2 10.1.1.102, ULXD-4 10.1.1.106 (shure-wireless); PSM_1 .103, PSM_2 .104, PSM_3 .105 (shure-psm1000) @ NA Ingest Companion connections; addresses read from Companion db every 60 s, config host = fallback | today: Companion UI; config hidden tiles axient1/2, ulxd, psm1-3 (channels 4/4/1/2/2/2) | Verify: connections good; ping each. Panel: RF group (battery, interference, NO PING) | other campus: RF inventory per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: ableton (ableton-osc), AbletonOSC (generic-osc), AbleSet (OFF) -> Tracks Mac @ NA Ingest Companion connections | today: Companion UI | Verify: 'ableton' good. Panel: APPS (ABLETON), rs_ableton watch conn:ableton | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: Propresenter-API (renewedvision-propresenter-api) -> ProPresenter Mac @ NA Ingest Companion connection 'Propresenter-API' (ignore_warning:true in config) | today: Companion UI | Verify: connection good. Panel: APPS (PROPRES OFFLINE) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: BibleTV (generic-osc) -> Bible TV PC @ NA Ingest Companion connection 'BibleTV' | today: Companion UI | Verify: connection good. Panel: APPS (BIBLE OSC) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: lighting-midi (generic-midi) -> Lighting PC @ NA Ingest Companion connection 'lighting-midi' | today: Companion UI | Verify: connection good. Panel: MIDI (COMPANION MIDI) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: OBS-Youtube (obs-studio) -> LiveStream PC @ NA Ingest Companion connection 'OBS-Youtube' (service_only:true) | today: Companion UI | Verify: connection good. Panel: OBS, STREAM group; obs fix reconnects it | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: arena (resolume-arena) -> Lighting PC :8080 @ NA Ingest Companion connection 'arena' | today: Companion UI | Verify: connection good. Panel: ARENA, VIDEO group | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: RESI_Decoder (resi-decoders, RossTalk) 10.1.10.203 and resi-studio-cues @ NA Ingest Companion connections | today: Companion UI | Verify: connections good; ping 10.1.10.203. Panel: RESI, STREAM group | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: Companion connections :: VX1000 10.1.14.116 and UHDJr 10.1.14.115 (novastar-controller) @ NA Ingest Companion connections | today: Companion UI | Verify: connections good AND ping (module keeps saying Connected when off). Panel: LED, VIDEO group | other campus: LED processors per site
|
||
|
|
- [runtime-data] NA Ingest: Companion connections :: Connections NOT watched by the panel @ NA Ingest Companion: 7 Govee lights, DiGiCo_OSC (OFF), m32 (OFF), AbleSet (OFF), tcp-HyperDeck-1..6 | today: Companion UI | Verify: /api/connections. Panel: none (candidates to add via the UI) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Resi bridge LaunchAgent org.waterschurch.resi-propresenter @ NA Ingest: ~/Library/LaunchAgents/org.waterschurch.resi-propresenter.plist -> /usr/bin/python3 '~/Library/Application Support/resi-propresenter/resi_to_propresenter.py' (KeepAlive, RunAtLoad) | today: separate project, installed by hand; fix 'bridge' = launchctl kickstart -k / bootstrap | Verify: launchctl list | grep resi-propresenter (PID 843). Panel: INGEST (BRIDGE), rs_bridge. Never restart during a service (guideline 10) | other campus: only where ProPresenter stage countdown to Resi cues is used
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Lobby captions server LaunchAgent org.waterschurch.lobby-captions @ NA Ingest: ~/Library/LaunchAgents/org.waterschurch.lobby-captions.plist -> /usr/bin/python3 ~/LobbyCaptions/server.py --channels Speaker,MC | today: separate project; fix 'captions' kickstarts both captions agents | Verify: launchctl list | grep lobby-captions (PID 837). Panel: INGEST (CAPTIONS), rs_captions | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Lobby caption screen LaunchAgent org.waterschurch.lobby-captions-display @ NA Ingest: ~/Library/LaunchAgents/org.waterschurch.lobby-captions-display.plist -> ~/LobbyCaptions/LobbyCaptionsDisplay.app --config ~/LobbyCaptions/display.json | today: separate project; fix 'caption_screen' | Verify: launchctl list (PID 838). Panel: INGEST (CAPTION SCREEN) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: ProdCom.app (transcription, HTTP :24480) @ NA Ingest: /Applications/ProdCom.app (running PID 548); check http://127.0.0.1:24480/api/v1/ping every 5 s; fix 'prodcom' pkill/open; also restarted after dvs_ingest | today: how it starts at login NOT determined (not a login item, not a LaunchAgent) | Verify: curl 127.0.0.1:24480/api/v1/ping; pgrep -x ProdCom. Panel: INGEST (PRODCOM DOWN), rs_prodcom | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: ProdDash.app (login item, HTTP :24500) @ NA Ingest: /Applications/ProdDash.app (login item; launchd shows application.org.waterschurch.proddash.*); checks process match + http://127.0.0.1:24500/ every 10 s; fix 'proddash' | today: macOS login item | Verify: curl -I 127.0.0.1:24500; pgrep -x ProdDash. Panel: INGEST (PRODDASH), rs_proddash | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Spotify.app + playlist Christian EDM 2026 @ NA Ingest: ~/Applications/Spotify.app (NOT /Applications); playlist spotify:playlist:2uTpJVYQLFnKF1WnSOuco8 | today: installed by hand; playlist URI hardcoded in config twice (check + fix run string) | Verify: pgrep -x Spotify; SPOTIFY key 'PLAYING'. Panel: SPOTIFY, rs_spotify, SHOW group | other campus: playlist per site; open -g -a Spotify works wherever the app is
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: ATEM Software Control (login item) + midiEnabled preference @ NA Ingest: /Applications/Blackmagic ATEM Switchers/ATEM Software Control.app; defaults domain 'com.blackmagic-design.ATEM Software Control' key midiEnabled must be 0 (pref check; fix atem_midi quits/reopens the app) | today: installed with ATEM Switchers package; login item | Verify: defaults read 'com.blackmagic-design.ATEM Software Control' midiEnabled -> 0. Panel: ATEM (ATEM SW MIDI ON) | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Dante Virtual Soundcard on NA Ingest (root LaunchDaemon) @ NA Ingest: /Library/LaunchDaemons com.audinate.dante.DanteVirtualSoundcard (dvsd, apec, conmon_server, ptp running); state wantToRun in /Library/Preferences/com.audinate.dante.dvs.plist; Dante name STUDIO-A-Ingest on en17 | today: Audinate installer; fix dvs_ingest = sudo -n /usr/local/sbin/status-panel-dvs-start && open -g -a DVS, then ProdCom restart | Verify: pgrep -f DanteVirtualSoundcard/apec; defaults read /Library/Preferences/com.audinate.dante.dvs wantToRun -> 1. Panel: DANTE (INGEST GONE), rs_dvs_ingest | other campus: per Mac with DVS
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Church Translate DISABLED on NA Ingest @ NA Ingest: ~/Library/LaunchAgents.disabled/org.waterschurch.translate.plist (open -a Church Translate; must NOT run here, it runs on NA Translation) | today: moved out of ~/Library/LaunchAgents by hand 2026-10-08 | Verify: launchctl list | grep translate -> nothing; pgrep -x 'Church Translate' -> nothing on NA Ingest | other campus: document which Mac owns each app
|
||
|
|
- [external-setup] NA Ingest: apps the panel watches :: Google Drive (ATEM restore file source) @ NA Ingest: ~/Library/CloudStorage/GoogleDrive-media@waterschurch.org (login item 'Google Drive'); restore file Backup/NA/ATEM/'4k plus 2026-10-07 14-59-55.xml' copied to repo atem-reference.xml | today: copy a new restore XML over atem-reference.xml in the repo, re-run install.sh | Verify: ls that CloudStorage folder; cmp repo atem-reference.xml with the Drive file. Panel: ATEM AUDIO/CAMERA reference | other campus: each site keeps its own restore XML
|
||
|
|
- [runtime-data] NA Ingest: apps the panel watches :: Free disk on / @ NA Ingest: shutil.disk_usage('/') every 10 s; warn_gb 25, err_gb 8 | today: config tiles.ingest disk check | Verify: df -g /. Panel: INGEST (DISK xGB) | other campus: thresholds per site
|
||
|
|
- [runtime-data] NA Ingest: other background tasks (not the panel) :: org.waterschurch.checklist-build-runner (Gitea act-runner daemon) @ NA Ingest: ~/Library/LaunchAgents/org.waterschurch.checklist-build-runner.plist -> ~/act-runner/gitea-runner daemon (KeepAlive) | today: other project (checklist app); not touched by the panel | Verify: launchctl list (PID 839). Shows on the machine map only | other campus: n/a
|
||
|
|
- [runtime-data] NA Ingest: other background tasks (not the panel) :: org.waterschurch.checklist-drive-backup (calendar) and checklist-weekly-health (calendar) @ NA Ingest: ~/Library/LaunchAgents/... -> ~/checklist-app/backup-to-drive.sh and ~/checklist-app/scripts/weekly-health.sh (StartCalendarInterval, RunAtLoad false) | today: other project | Verify: launchctl list shows them with '-' (idle). Machine map only | other campus: n/a
|
||
|
|
- [runtime-data] NA Ingest: other background tasks (not the panel) :: Other login items / agents: Itsycal, Alfred 5, Google Drive, Google Updater/keystone, Signiant (local.launch.signiantapp) @ NA Ingest: login items list + ~/Library/LaunchAgents | today: by hand | Verify: osascript 'tell application "System Events" to get the name of every login item'. Machine map only | other campus: n/a
|
||
|
|
- [external-setup] NA Ingest: network :: en0 10.1.1.1 (main LAN, gateway 10.1.0.1) and second address 10.6.3.222 @ NA Ingest: config network.interface en0, network.gateway 10.1.0.1; windows-setup.ps1:18 allows SSH only from 10.1.1.1 and 10.6.3.222 (which interface carries 10.6.3.222 NOT determined) | today: macOS network settings; IPs hardcoded in windows-setup.ps1 | Verify: ipconfig getifaddr en0; ifconfig | grep 10.6.3.222; ping 10.1.0.1. Panel: NET (link, gateway, blips) | other campus: Ingest IPs per site must be edited in windows-setup.ps1 and config
|
||
|
|
- [external-setup] NA Ingest: network :: en17 Dante port 169.254.144.168 (STUDIO-A-Ingest) @ NA Ingest: en17; arp -an on it feeds the Dante map | today: physical cabling + DVS interface choice | Verify: ipconfig getifaddr en17; dante-map.json lists STUDIO-A-Ingest on 10.66.1.102 0/3 | other campus: per site
|
||
|
|
- [external-setup] NA Ingest: network :: en20 10.66.1.2 Netgear management link @ NA Ingest: en20 -> switches 10.66.1.100 and 10.66.1.102 (telnet 23); NETGEAR Engage.app also on this Mac | today: physical link + static IP by hand; config dante_switches | Verify: ipconfig getifaddr en20; nc -z 10.66.1.100 23. Panel: DANTE PoE power-cycle, map | other campus: switch IPs per site
|
||
|
|
- [external-setup] ProPresenter Mac :: Host 'prop' napropresenter@10.1.14.225 ('NA ProPresenter Mac (2)', macOS 26.2) @ config hosts.prop.ssh; Remote Login ON (System Settings > Sharing) | today: Remote Login by hand; key via mac-authorize.sh (ARD Send UNIX Command as root) | Verify: ssh -i ~/.ssh/id_status_panel napropresenter@10.1.14.225 hostname (ok today). Panel: APPS (PROPRES NOT RUNNING, PROP TV DOWN), MIDI (PROP LIGHTS), DANTE (PROP MAC) | other campus: user@ip per site
|
||
|
|
- [secret] ProPresenter Mac :: authorized_keys entry status-panel@NA-Ingest @ ProPresenter Mac: ~napropresenter/.ssh/authorized_keys (1 line today) | today: remote-access/mac-authorize.sh pasted into ARD (public key hardcoded in the script) | Verify: grep -c status-panel ~/.ssh/authorized_keys -> 1 | other campus: new site = new key pair -> edit the hardcoded key in mac-authorize.sh and windows-setup.ps1
|
||
|
|
- [secret] ProPresenter Mac :: DVS helper /usr/local/sbin/status-panel-dvs-start + /etc/sudoers.d/status-panel @ ProPresenter Mac: root-owned 755 script (defaults write wantToRun 1; launchctl kickstart -k system/com.audinate.dante.DanteVirtualSoundcard) + sudoers NOPASSWD for that one script (installed 2026-10-08 12:05) | today: remote-access/mac-dvs-helper.sh via ARD as root; undo: rm both files | Verify: sudo -n -l /usr/local/sbin/status-panel-dvs-start (sudo-ok today); ls -l both. Panel: fix dvs_prop, rs_dvs_prop | other campus: run the same script on each DVS Mac
|
||
|
|
- [external-setup] ProPresenter Mac :: Dante Virtual Soundcard engine (NA-ProPresenter-Mac) @ ProPresenter Mac: root LaunchDaemon com.audinate.dante.DanteVirtualSoundcard; wantToRun=1; engine running today | today: Audinate installer | Verify: pgrep -f DanteVirtualSoundcard/apec; Companion Dante devices list has NA-ProPresenter-Mac. Panel: DANTE PROP MAC GONE | other campus: per Mac
|
||
|
|
- [external-setup] ProPresenter Mac :: ProPresenter app (newest /Applications/ProPresenter*.app, 21.4) + API :1025 @ ProPresenter Mac: fix propresenter = pkill + open newest; checks pgrep -xq ProPresenter (SSH every 10 s) and http://10.1.14.225:1025/ every 5 s | today: installed by hand; API enabled in ProPresenter prefs | Verify: curl -I http://10.1.14.225:1025/; ssh ... pgrep -x ProPresenter. Panel: APPS, rs_propres | other campus: per site
|
||
|
|
- [external-setup] ProPresenter Mac :: Network MIDI session 'NA ProP' with peer Lighting PC (10.1.10.206:5004) @ ProPresenter Mac: CoreMIDI network driver (read via the ssh python stream; reconnect via connect_peer over ssh) | today: Audio MIDI Setup on that Mac by hand; config tiles.midi check PROP LIGHTS | Verify: MIDI key has no 'PROP LIGHTS'; log of the stream. Panel: MIDI | other campus: session/peer names per site
|
||
|
|
- [external-setup] Tracks Mac :: Host 'tracks' waterschurchmedia@10.1.3.227 (Ableton Live 11 Suite + DVS) @ config hosts.tracks.ssh; Remote Login turned ON 2026-10-08 (was off) | today: Remote Login by hand; key via mac-authorize.sh (ARD) | Verify: ssh ... hostname. TODAY: 'Host is down' at 10.1.3.227 (Mac off or asleep). Panel: APPS (ABLETON NOT RUNNING, TRACKS MAC ping), MIDI (FX LIGHTS, TRK LIVEBOX, TRK STUDIO B, TRACKS MIDI), DANTE (TRACKS) | other campus: per site
|
||
|
|
- [secret] Tracks Mac :: authorized_keys entry + DVS helper + sudoers @ Tracks Mac: ~/.ssh/authorized_keys; /usr/local/sbin/status-panel-dvs-start; /etc/sudoers.d/status-panel (verified installed 2026-10-08 per memory; NOT re-verified today, host down) | today: mac-authorize.sh and mac-dvs-helper.sh via ARD as root | Verify when up: grep -c status-panel ~/.ssh/authorized_keys; sudo -n -l /usr/local/sbin/status-panel-dvs-start. Panel: fix dvs_tracks, rs_dvs_tracks | other campus: same scripts
|
||
|
|
- [external-setup] Tracks Mac :: Ableton Live 11 Suite + last-set lookup @ Tracks Mac: /Applications/Ableton Live 11 Suite.app; last set parsed from ~/Library/Preferences/Ableton/Live*/Log.txt ('Loading document', templates skipped) by fixes ableton / ableton_restart | today: app installed by hand; app name hardcoded in both fix strings | Verify: ssh ... pgrep -x Live; Companion 'ableton' good. Panel: APPS, rs_ableton | other campus: Live version/app name per site
|
||
|
|
- [external-setup] Tracks Mac :: Network MIDI session 'NA Tracks' (peers Lighting PC 10.1.10.206:5004, SuperRack-LiveBox 10.1.13.140:5004, Studio B Mac Studio via Bonjour) + Bonjour advert 'NA Tracks' @ Tracks Mac: CoreMIDI network driver; read by the ssh stream; mDNS instance seen from NA Ingest | today: Audio MIDI Setup on the Tracks Mac by hand; config midi_peer checks with host tracks | Verify: dns-sd -B _apple-midi._udp shows 'NA Tracks'; MIDI key clean. Panel: MIDI (FX LIGHTS, TRK LIVEBOX, TRK STUDIO B, TRACKS MIDI GONE) | other campus: per site
|
||
|
|
- [external-setup] Tracks Mac :: Dante Virtual Soundcard (NA-Tracks) @ Tracks Mac: root LaunchDaemon com.audinate.dante.DanteVirtualSoundcard | today: Audinate installer | Verify: Dante devices list has NA-Tracks. Panel: DANTE TRACKS GONE | other campus: per Mac
|
||
|
|
- [external-setup] NA Translation Mac mini :: Host 'translation' studio@10.1.7.39 ('NA Translation', macOS 26.5.1) @ config hosts.translation.ssh; Remote Login ON | today: Remote Login by hand; key via mac-authorize.sh | Verify: ssh ... hostname (ok today). Panel: APPS (TRANSLATE NOT RUNNING), DANTE (TRANSL) | other campus: per site
|
||
|
|
- [secret] NA Translation Mac mini :: authorized_keys + DVS helper + sudoers @ NA Translation: ~/.ssh/authorized_keys (1); /usr/local/sbin/status-panel-dvs-start; /etc/sudoers.d/status-panel (installed 2026-10-08 12:05, sudo-ok today) | today: mac-authorize.sh and mac-dvs-helper.sh via ARD as root | Verify: sudo -n -l /usr/local/sbin/status-panel-dvs-start. Panel: fix dvs_translation, rs_dvs_transl | other campus: same scripts
|
||
|
|
- [external-setup] NA Translation Mac mini :: Church Translate.app (+ its translation server) @ NA Translation: /Applications/Church Translate.app; checks pgrep -xq 'Church Translate'; fixes translate (open if closed) / translate_restart (kills process group then open) | today: installed by hand | Verify: ssh ... pgrep -x 'Church Translate'. Panel: APPS, rs_translate | other campus: per site
|
||
|
|
- [external-setup] NA Translation Mac mini :: Dante Virtual Soundcard (NA-Translation) @ NA Translation: root LaunchDaemon; wantToRun=1, engine running today | today: Audinate installer | Verify: pgrep -f DanteVirtualSoundcard/apec. Panel: DANTE TRANSL GONE | other campus: per Mac
|
||
|
|
- [external-setup] Studio B Mac Studio :: Host 'studiob' studiob@10.1.13.175 ('NA Studio B (4)', macOS 26.5) @ config hosts.studiob.ssh; Remote Login ON; authorized_keys (1) | today: Remote Login by hand; key via mac-authorize.sh | Verify: ssh ... hostname (ok today). Panel: APPS (PT SOLO NOT AFL, PT SOLO CHECK OFF), MIDI (TRK STUDIO B) | other campus: per site
|
||
|
|
- [external-setup] Studio B Mac Studio :: Solo-mode helper LaunchAgent org.waterschurch.status-panel.solo-mode @ Studio B: ~/Library/LaunchAgents/org.waterschurch.status-panel.solo-mode.plist -> ~/Library/Application Support/status-panel/solo-mode-agent (compiled with /usr/bin/swiftc from remote-access/solo-mode-agent.swift; KeepAlive); running PID 1051 | today: scp solo-mode-agent.swift + install-solo-mode.sh to /tmp on that Mac, then ssh 'zsh /tmp/install-solo-mode.sh' (needs swiftc = Xcode CLT there) | Verify: launchctl list | grep solo-mode; solo-mode.json younger than 20 s with trusted:true. Panel: APPS PT SOLO checks, fix solo_afl | other campus: only where Pro Tools solo mode must be watched
|
||
|
|
- [runtime-data] Studio B Mac Studio :: solo-mode.json (state) and solo-mode.fix (trigger file) @ Studio B: ~/Library/Application Support/status-panel/solo-mode.json written every 1 s ({afl, latch, bad, running, trusted, time, error}); touching solo-mode.fix makes the helper tick AFL+Latch | today: helper writes json; fix solo_afl touches .fix over ssh then greps json | Verify: cat solo-mode.json (today afl:true latch:true trusted:true). Panel: APPS | other campus: same
|
||
|
|
- [secret] Studio B Mac Studio :: Accessibility permission for solo-mode-agent (TCC) @ Studio B: System Settings > Privacy & Security > Accessibility > solo-mode-agent allowed | today: allowed by hand once on that Mac's screen (the helper prompts via AXIsProcessTrustedWithOptions), then helper restart | Verify: solo-mode.json trusted:true (true today); otherwise panel says PT SOLO CHECK OFF | other campus: must be re-granted after recompiling the binary
|
||
|
|
- [external-setup] Studio B Mac Studio :: Pro Tools.app @ Studio B: /Applications/Pro Tools.app (bundle com.avid.ProTools); Options > Solo Mode must be AFL + Latch | today: installed by hand | Verify: solo-mode.json running:true. Panel: APPS | other campus: per site
|
||
|
|
- [external-setup] Studio B Mac Studio :: MIDI peer 'Studio B Mac Studio' in the NA Tracks session (Bonjour address '\tStudio B Mac Studio\tlocal.') @ config tiles.midi check TRK STUDIO B; reconnect via Tracks Mac | today: Audio MIDI Setup on Studio B / Tracks by hand | Verify: MIDI key clean. Panel: MIDI | other campus: per site
|
||
|
|
- [external-setup] Lighting PC :: Host 'lighting' media@10.1.10.206 (LIGHTING-PC, Windows; firewall blocks ping) @ config hosts.lighting.ssh; no MAC (no Wake-on-LAN entry) | today: windows-setup.ps1 run by hand as administrator (Set-ExecutionPolicy RemoteSigned CurrentUser first) | Verify: ssh ... 'echo %COMPUTERNAME%' (ok today). Panel: VISTA, ARENA, MIDI (LIGHT PC, FX LIGHTS, PROP LIGHTS, LIGHT PC MIDI GONE) | other campus: per site
|
||
|
|
- [external-setup] Lighting PC :: OpenSSH Server service sshd (Automatic, restarts on failure) @ Lighting PC: Windows capability OpenSSH.Server; sc failure sshd restart/5000 x3 (windows-setup.ps1:21-40) | today: windows-setup.ps1 step 1 | Verify: sc query sshd -> RUNNING (yes today) | other campus: same script
|
||
|
|
- [external-setup] Lighting PC :: Firewall rule OpenSSH-Server-In-TCP (Profile Any, RemoteAddress 10.1.1.1,10.6.3.222) @ Lighting PC: Windows Defender Firewall inbound rule Name OpenSSH-Server-In-TCP / DisplayName 'OpenSSH Server (sshd)' (windows-setup.ps1:41-47) | today: windows-setup.ps1 step 1 (needs the user's OK for firewall changes, guideline 12) | Verify: PowerShell Get-NetFirewallRule -Name OpenSSH-Server-In-TCP | Get-NetFirewallAddressFilter (netsh by display name found nothing today, so NOT confirmed) | other campus: Ingest IPs hardcoded in the script
|
||
|
|
- [secret] Lighting PC :: authorized keys: C:\ProgramData\ssh\administrators_authorized_keys + %USERPROFILE%\.ssh\authorized_keys @ Lighting PC: both files hold status-panel@NA-Ingest; ACL Administrators+SYSTEM only (windows-setup.ps1:49-61) | today: windows-setup.ps1 step 2 | Verify: key login works (it does today) | other campus: public key hardcoded in the script
|
||
|
|
- [external-setup] Lighting PC :: Scheduled task \StatusPanel\Start Vista @ Lighting PC: task runs <drive>\Vista3\Vista.exe (G:) as the interactive user, Limited; fix 'vista' = schtasks /Run (Status: Running today; Vista.exe up) | today: windows-setup.ps1 step 3 (app auto-discovered) | Verify: schtasks /Query /TN \StatusPanel\Start Vista; tasklist | findstr Vista.exe. Panel: VISTA hold + auto-fix | other campus: the script finds the apps present on that PC
|
||
|
|
- [external-setup] Lighting PC :: Vista autoload preference (opens Prop Takeover) @ Lighting PC: E:\media\Documents\Vista 3\.preferences <autoloadpath> -> E:\media\Documents\Vista 3\Shows (set by hand 2026-10-08) | today: edited by hand on the PC (not in any script) | Verify: open the .preferences file; starting Vista loads the show. Panel: VISTA fix opens the right show (guideline 6) | other campus: per site show path
|
||
|
|
- [external-setup] Lighting PC :: Scheduled task \StatusPanel\Start Arena (Resolume Arena, web :8080) @ Lighting PC: C:\Program Files\Resolume Arena*\Arena.exe; fix 'arena' then Companion reconnect (Running today) | today: windows-setup.ps1 step 3 | Verify: schtasks /Query /TN \StatusPanel\Start Arena; tasklist | findstr Arena.exe; Companion arena good. Panel: ARENA | other campus: same
|
||
|
|
- [external-setup] Lighting PC :: Scheduled task \StatusPanel\Start rtpMIDI (tray app) + rtpMIDIService (restarts itself on failure) @ Lighting PC: C:\Program Files (x86)\Tobias Erichsen\rtpMIDI\rtpMIDI.exe; service rtpMIDIService sc failure restart/5000 (windows-setup.ps1:112-116); fix rtpmidi_start = net start service, then task; NEVER restart a running rtpMIDI | today: windows-setup.ps1 step 3 | Verify: sc query rtpMIDIService -> RUNNING (yes); tasklist rtpMIDI.exe -> NOT running today (tray app closed; sessions live in the service). Panel: MIDI LIGHT PC MIDI GONE fix | other campus: same
|
||
|
|
- [external-setup] Lighting PC :: Network profile must stay Public (rtpMIDISvc Bonjour firewall rules are Public-only) @ Lighting PC: Windows network category; firewall rules named rtpMIDISvc (26 rules seen today) | today: by hand; README MIDI row (2026-10-08) | Verify: Get-NetConnectionProfile NetworkCategory = Public; dns-sd on NA Ingest shows 'Lighting PC' | other campus: same gotcha on any Windows rtpMIDI PC
|
||
|
|
- [runtime-data] Lighting PC :: Art-Net polls from 10.1.10.206 to UDP 6454 (Vista heartbeat) @ config tiles.vista artnet check source 10.1.10.206 max_silence 5 s | today: Vista sends ArtPoll every 0.5 s by itself | Verify: VISTA key green. Panel: VISTA SILENT | other campus: source IP per site
|
||
|
|
- [external-setup] Lighting PC :: rtpMIDI session peer 'Lighting PC' 10.1.10.206:5004 in NA Ingest / NA Tracks / NA ProP sessions @ config tiles.midi midi_peer checks LIGHT PC, FX LIGHTS, PROP LIGHTS (address 10.1.10.206:5004) | today: rtpMIDI UI on the PC + Audio MIDI Setup on the Macs by hand | Verify: MIDI key clean. Panel: MIDI, hold = midi_reconnect from the Mac side | other campus: peer name/address per site
|
||
|
|
- [external-setup] LiveStream PC :: Host 'livestream' media@10.1.9.126 (LIVESTREAM, Windows) + Wake-on-LAN mac 6c:24:08:d7:fb:57 broadcast 10.1.255.255 @ config hosts.livestream (ssh, mac, wake_broadcast); wake_on_lan status_panel.py:1759 sends UDP 9 magic packet when ssh exits 255 | today: windows-setup.ps1 (sshd, key, WoL adapter) + BIOS WoL by hand | Verify: ssh ... 'echo %COMPUTERNAME%' (ok today); Get-NetAdapterPowerManagement Ethernet WakeOnMagicPacket Enabled (yes today). Panel: OBS (WAKING PC) | other campus: MAC/broadcast per site
|
||
|
|
- [secret] LiveStream PC :: sshd + firewall rule + authorized keys @ LiveStream PC: sshd RUNNING today; OpenSSH-Server-In-TCP rule; administrators_authorized_keys + user authorized_keys | today: windows-setup.ps1 steps 1-2 | Verify: sc query sshd; key login works | other campus: same script
|
||
|
|
- [external-setup] LiveStream PC :: Scheduled task \StatusPanel\Start OBS (RunLevel Highest, --disable-shutdown-check) @ LiveStream PC: D:\Program Files\obs-studio\bin\64bit\obs64.exe ticked 'Run as administrator' so the task runs elevated (windows-setup.ps1:84-86,101); fix 'obs' then Companion reconnect (task Ready, obs64.exe running today) | today: windows-setup.ps1 step 3 | Verify: schtasks /Query /TN \StatusPanel\Start OBS; tasklist obs64.exe; Companion OBS-Youtube good. Panel: OBS | other campus: same
|
||
|
|
- [external-setup] Bible TV PC :: Host 'bibletv' media@10.6.7.13 (SANCTUARYTV, Windows 11, Wi-Fi only, blocks ping) @ config hosts.bibletv.ssh; checked via http://10.6.7.13:8080/ every 5 s | today: windows-setup.ps1 by hand | Verify: ssh ... (ok today); curl -I http://10.6.7.13:8080/. Panel: APPS (BIBLE APP DOWN, BIBLE OSC) | other campus: per site
|
||
|
|
- [secret] Bible TV PC :: sshd + firewall rule + authorized keys @ Bible TV PC: sshd RUNNING today; rule + keys per windows-setup.ps1 | today: windows-setup.ps1 steps 1-2 | Verify: sc query sshd; key login works | other campus: same script
|
||
|
|
- [external-setup] Bible TV PC :: Scheduled task \StatusPanel\Start BibleApp (also AtLogOn + 15 s) @ Bible TV PC: 'Bible App.exe' found by the script; task Running today (4 Bible App.exe processes); fix bibleapp = taskkill then schtasks /Run | today: windows-setup.ps1 step 3 (AtLogon true) | Verify: schtasks /Query /TN \StatusPanel\Start BibleApp; tasklist | findstr Bible. Panel: APPS hold (never auto) | other campus: same
|
||
|
|
- [external-setup] Bible TV PC :: Wi-Fi power settings (power plan wireless = max performance; adapter PnPCapabilities=24) @ Bible TV PC: powercfg + registry (set by hand 2026-10-11; not in any script) | today: by hand | Verify: powercfg /q (wireless adapter settings); Ethernet recommended instead | other campus: only Wi-Fi machines
|
||
|
|
- [external-setup] Devices: video :: ATEM switcher 10.1.10.2 @ Companion 'ATEM' connection + atem_watch.js direct connection; reference atem-reference.xml | today: config atem.host; restore file copied by hand | Verify: ATEM key green; ping 10.1.10.2. Panel: ATEM | other campus: IP + XML per site
|
||
|
|
- [external-setup] Devices: video :: HyperDecks 1-6 (IPs set on the Companion connections; control port 9993) @ Companion HyperDeck_n; watchdog reads var 'ip' and the db; hold = connection off/on + 15 s check; never reboots | today: Companion UI; config tiles hd1..hd6 (optional:true on HD2/HD4) | Verify: nc -z <deck ip> 9993; HD keys green. Panel: HD1-6 | other campus: deck count/optional flags per site
|
||
|
|
- [external-setup] Devices: video :: LED processors VX1000 10.1.14.116, UHDJr 10.1.14.115 @ Companion novastar connections + pings | today: config tiles.led | Verify: ping both. Panel: LED | other campus: per site
|
||
|
|
- [external-setup] Devices: audio/RF :: Tascam DA-6400 10.1.11.74 @ Companion 'tascam' + ping | today: config tiles.tascam | Verify: ping; Companion good. Panel: TASCAM | other campus: per site
|
||
|
|
- [external-setup] Devices: audio/RF :: X32 (STUDIO-A-X32 on Dante too) @ Companion 'x32' (address on the connection) | today: Companion UI | Verify: Companion good. Panel: X32 | other campus: per site
|
||
|
|
- [external-setup] Devices: audio/RF :: Shure AD4Q x2 (10.1.1.101/.102), ULXD4 (.106), PSM1000 x3 (.103-.105) @ Companion Shure connections + 3 s pings | today: config hidden RF tiles | Verify: ping each; RF key green. Panel: RF | other campus: per site
|
||
|
|
- [external-setup] Devices: audio/RF :: SuperRack LiveBox 10.1.13.140:5004 (MIDI peer) / FOH-SuperRack-LiveBox (Dante) @ config midi_peer SUPERRACK + TRK LIVEBOX; Dante map 10.66.1.102 0/9 | today: config | Verify: MIDI key clean; Dante list. Panel: MIDI, DANTE | other campus: per site
|
||
|
|
- [external-setup] Devices: Resi/LED/network :: Resi decoder 10.1.10.203 (RossTalk) and encoder 10.1.10.202 (LAOEncoder web), Resi cloud https://central.resi.io/ @ Companion RESI_Decoder + resi-studio-cues; pings; HEAD http checks every 10 s / 30 s | today: config tiles.resi | Verify: ping .203 .202; curl -I http://10.1.10.202/; curl -I https://central.resi.io/. Panel: RESI | other campus: per site
|
||
|
|
- [external-setup] Devices: Resi/LED/network :: Gateway 10.1.0.1 + NA Ingest link en0 @ config network (gateway, interface, burst_* thresholds, remember_seconds 300) | today: config | Verify: ping 10.1.0.1; ifconfig en0 'status: active'. Panel: NET (BLIP) | other campus: per site
|
||
|
|
- [external-setup] Dante network :: Netgear M4250 switches 10.66.1.100 (8G2XF-PoE+) and 10.66.1.102 (26G4XF-PoE+), telnet CLI port 23, fw 13.0.5.24 @ config dante_switches; netgear.py (Switch class, survey, poe_cycle_device; MAX_SHARED 2) | today: switches managed in NETGEAR Engage; IPs in config | Verify (GUI session on NA Ingest, not over ssh): python3 netgear.py lookup <mac>; python3 netgear.py poe-status 10.66.1.102 0/14. Panel: DANTE hold power-cycle (dante-auto), dante-map | other campus: switch IPs + keychain login per site
|
||
|
|
- [runtime-data] Dante network :: Studio B PoE-powered Dante boxes (MON 0/15, SOLO-MON 0/14, TB 0/16, TB-MON 0/17 on 10.66.1.102) + other 15 hardware devices @ dante-map.json; config dante check fix map ('*': dante-auto) | today: automatic by MAC; no config edit when re-patched | Verify: dante-map.json shows poe:true on those four. Panel: DANTE hold = PoE reset for them, Companion module restart for the rest | other campus: automatic
|
||
|
|
- [secret] Secrets & permissions :: SSH key pair id_status_panel (private on NA Ingest) @ NA Ingest: ~/.ssh/id_status_panel + .pub (config ssh_key); comment status-panel@NA-Ingest; public key HARDCODED in remote-access/mac-authorize.sh:5 and windows-setup.ps1:17 | today: generated 2026-10-08 by hand; never leaves NA Ingest | Verify: ls -l ~/.ssh/id_status_panel; ssh-keygen -lf id_status_panel.pub matches the key in the scripts | other campus: each site Ingest Mac makes its own key; the UI must generate/show the public key and feed it into the setup scripts instead of the hardcoded line
|
||
|
|
- [secret] Secrets & permissions :: known_hosts (accept-new) @ NA Ingest: ~/.ssh/known_hosts (+ .old); ssh_cmd uses StrictHostKeyChecking=accept-new | today: first connection records the host key automatically | Verify: ssh-keygen -F 10.1.14.225 etc. A reinstalled machine with a new host key makes every check fail until the old line is removed | other campus: same
|
||
|
|
- [secret] Secrets & permissions :: Netgear login in NA Ingest login keychain (service netgear-status-panel, account admin) @ NA Ingest: login keychain generic password; read by netgear.credentials() via /usr/bin/security; only readable in the GUI session (LaunchAgent), not over ssh | today: security add-generic-password -s netgear-status-panel -a admin -w, typed by the user in Terminal on NA Ingest | Verify: security find-generic-password -s netgear-status-panel (attributes only; exists today, acct admin); dante-map log line appears. Panel: DANTE PoE, dante-map | other campus: store the item on each site's Ingest Mac; never typed by Claude (guideline 11)
|
||
|
|
- [secret] Secrets & permissions :: sudoers NOPASSWD for the DVS helper (4 Macs) @ NA Ingest, ProPresenter Mac, Tracks Mac, NA Translation: /etc/sudoers.d/status-panel '<user> ALL=(root) NOPASSWD: /usr/local/sbin/status-panel-dvs-start' (visudo-checked) | today: mac-dvs-helper.sh via ARD as root (NA Ingest 2026-10-08 12:38, others 12:05) | Verify: sudo -n -l /usr/local/sbin/status-panel-dvs-start on each (ok on Ingest, ProP, Translation today; Tracks not reachable). Panel: DVS fixes | other campus: same script
|
||
|
|
- [secret] Secrets & permissions :: Accessibility (TCC) for solo-mode-agent on Studio B @ Studio B: Privacy & Security > Accessibility | today: granted by hand on that Mac's screen | Verify: solo-mode.json trusted:true | other campus: per Mac; re-grant after rebuild
|
||
|
|
- [secret] Secrets & permissions :: Automation (TCC) for the watchdog to control Spotify via osascript @ NA Ingest: Privacy & Security > Automation (python3 / launchd context -> Spotify); prompt appears on NA Ingest's screen | today: NOT determined how/when it was granted; Spotify hold works per the user, and poll_spotify logs an error string if osascript is refused | Verify: log has no 'spotify' osascript errors; SPOTIFY key shows PLAYING not '?'. Panel: SPOTIFY | other campus: grant once per Ingest Mac
|
||
|
|
- [secret] Secrets & permissions :: Remote Login (SSH) enabled on each Mac + ssh access group membership @ ProPresenter Mac, Tracks Mac, NA Translation, Studio B, NA Ingest: System Settings > General > Sharing > Remote Login (com.apple.access_ssh group; mac-authorize.sh prints ssh-group) | today: by hand (Tracks turned on 2026-10-08) | Verify: ssh from NA Ingest works; sudo systemsetup -getremotelogin on the Mac | other campus: per Mac
|
||
|
|
- [workflow-step] Secrets & permissions :: Apple Remote Desktop (ARD) used to push root commands to the Macs @ User's admin Mac: ARD > Manage > Send UNIX Command as root (used for mac-authorize.sh and mac-dvs-helper.sh) | today: user pastes the script text by hand | Verify: script prints 'OK user=... mac=...'. The UI can only show the text to paste, never run it | other campus: same
|
||
|
|
- [secret] Secrets & permissions :: Windows: run PowerShell as administrator + Set-ExecutionPolicy RemoteSigned (CurrentUser) @ Lighting, LiveStream, Bible TV PCs (windows-setup.ps1 header steps 2-3) | today: user does it at the PC; system/firewall changes need the user's OK (guideline 12) | Verify: the script's RESULT block (pc, user, sshd, nic mac/ip/network, tasks) | other campus: same
|
||
|
|
- [secret] Secrets & permissions :: MacBook keychain item gitea-mcp (git push credential) and key id_ed25519_checklist_ingest @ MacBook: login keychain; ~/.ssh/ | today: by hand | Verify: git push works; ssh checklist-ingest works | other campus: n/a | (need not be editable)
|
||
|
|
- [config-key] Secrets & permissions :: alert_webhook (empty today) @ config alert_webhook ''; post_webhook status_panel.py:2334 posts JSON {text} when Companion is down >30 s | today: config edit | string URL or ''. Verify: log 'webhook failed' absent | other campus: per site
|
||
|
|
- [workflow-step] Workflow steps :: Deploy the watchdog: scp + install.sh @ MacBook -> NA Ingest: scp status_panel.py coremidi.py netgear.py config.json install.sh atem_watch.js atem-reference.xml checklist-ingest:status-panel-install/; ssh checklist-ingest 'zsh ~/status-panel-install/install.sh' | today: by hand from the MacBook (README 'Changing things'); install.sh validates JSON, backs up config, restarts the agent | Verify: 'installed org.waterschurch.status-panel' echo; sp_hb fresh | other campus: same per site; the UI on the Ingest Mac should replace the scp step
|
||
|
|
- [workflow-step] Workflow steps :: Rebuild + import pages when the layout changes @ python3 make_page.py (imports status_panel.load_config); python3 push_page.py [--which restart] (tRPC WebSocket /trpc, Companion 5.0.7; refuses non-empty foreign pages) | today: by hand; only needed for tile positions/labels/new keys, not for check or fix edits | Verify: tablet view of pages 19/20; page_export name '19\nStatus' | other campus: same
|
||
|
|
- [workflow-step] Workflow steps :: Re-colour nav keys after pages move @ python3 nav_keys.py (--dry-run / --revert); nav_locations.json committed | today: by hand (guideline 9) | Verify: --dry-run reports nothing | other campus: same
|
||
|
|
- [workflow-step] Workflow steps :: Offline tests @ MacBook: python3 -m unittest discover -s tests (tests/test_status_panel.py, fake Companion, MIDI loopback; stubs ssh/fixes) | today: by hand before deploy (guideline 15) | Verify: all tests pass | other campus: same | (need not be editable)
|
||
|
|
- [workflow-step] Workflow steps :: One-shot poll without writing @ NA Ingest or MacBook: python3 status_panel.py --once (and --dry-run) | today: by hand | prints every tile row/col/level/text; useful as the UI's 'test this config' button | other campus: same
|
||
|
|
- [workflow-step] Workflow steps :: New ATEM restore file @ Copy the ATEM Software Control .xml from Google Drive Backup/NA/ATEM over repo atem-reference.xml, run install.sh (watchdog rebuilds atem-reference.json on start) | today: by hand | Verify: ATEM key green after restart | other campus: per site
|
||
|
|
- [workflow-step] Workflow steps :: Companion one-time setup per site @ Companion UI: create sp_state/sp_hb/sp_cmd, keep flash_tick_500 enabled, import pages, import tascam quiet module, name page '19\nStatus' | today: by hand (README 'One-time Companion setup') | Verify: custom-variable endpoints 200; trigger enabled | other campus: repeat per site
|
||
|
|
|