Sits between the classrooms, Companion and ProPresenter, and owns the truth about a parent call: validation, ids, the queue, expiry, duplicates, mode, approval, delivery, and every status a classroom is told. Companion is an operator surface and holds no state. Built after querying the church's own ProPresenter rather than working from the assumed contract, which turned out to be wrong in two ways: the message is called Parent Caller, not Parent Call, and its tokens are Name and Room rather than child and room. The finding that shaped the design is recorded in docs/propresenter-api.md. A trigger carrying a token name the message does not have still returns 204, and still puts the message on screen showing the previous call's values. So a 204 is not evidence on its own: the adapter reads the live message and refuses to trigger unless the configured tokens exist in it. Without that, a typo in .env would call the wrong child's parents and report success. Nothing claims more than it knows. A successful API call is reported as sent to sanctuary, never as displayed. The state machine is pure and synchronous, with time passed in and effects returned, so the awkward cases are testable properly: two rooms calling at once, an approval for the wrong id, an approval arriving after the request went stale, and a clear timer firing after the next call has gone up. The queue is in memory and dies with the process, because a parent call surfacing ten minutes late would be worse than one that was lost. 81 tests, then the whole thing end to end on Control: a request through the real broker and the real coordinator to the real ProPresenter, with the correct child and room on the sanctuary screen, the coordinator's own clear timer taking it down again, mode off sending nothing, and a duplicate id not sending twice.
54 lines
1.8 KiB
Bash
54 lines
1.8 KiB
Bash
# Parent Call coordinator — copy to .env and edit.
|
|
# Do not commit .env.
|
|
|
|
# --- MQTT -------------------------------------------------------------
|
|
MQTT_HOST=10.40.0.2
|
|
MQTT_PORT=1883
|
|
MQTT_USERNAME=
|
|
MQTT_PASSWORD=
|
|
MQTT_CLIENT_ID=parent-call-coordinator
|
|
|
|
# Topic root. No product name: the broker is the church's.
|
|
TOPIC_ROOT=classroom/parent-call
|
|
|
|
# --- ProPresenter -----------------------------------------------------
|
|
# The Mac running ProPresenter, and the port from its Network preferences.
|
|
PROPRESENTER_BASE_URL=http://10.30.0.2:1025
|
|
|
|
# The Message in ProPresenter this triggers, and the token names inside it.
|
|
# Verified on this church's ProPresenter 21.3 on 2026-09-06:
|
|
# the message is called "Parent Caller" and its tokens are
|
|
# capitalised. See docs/propresenter-api.md.
|
|
PROPRESENTER_MESSAGE=Parent Caller
|
|
PROPRESENTER_CHILD_TOKEN=Name
|
|
PROPRESENTER_ROOM_TOKEN=Room
|
|
|
|
# How long to wait on ProPresenter before calling it unreachable.
|
|
PROPRESENTER_TIMEOUT=4
|
|
|
|
# Clear the message automatically after this many seconds. 0 disables,
|
|
# and leaves clearing to the operator.
|
|
PROPRESENTER_CLEAR_AFTER=20
|
|
|
|
# How each room reads on the sanctuary screen. The message says
|
|
# "...please go to the {Room}", so these want to be room names as a
|
|
# person would say them. Unlisted rooms are title-cased.
|
|
ROOM_NAMES=nursery=Nursery,k2=K-2,older=Older Kids
|
|
|
|
# --- Behaviour --------------------------------------------------------
|
|
# A request older than this is never delivered.
|
|
REQUEST_TTL=180
|
|
|
|
# Longest child name and room name accepted from a classroom.
|
|
MAX_CHILD_LENGTH=40
|
|
MAX_ROOM_LENGTH=32
|
|
|
|
# How far ahead of us a classroom clock may be before we distrust it.
|
|
MAX_CLOCK_SKEW=120
|
|
|
|
# Mode when no retained mode exists on the broker yet.
|
|
DEFAULT_MODE=approval
|
|
|
|
# --- Health -----------------------------------------------------------
|
|
HEALTH_PORT=8099
|