Skip to content

Repository files navigation

talkingpoints-ha

Forward new TalkingPoints (Families) school messages to Home Assistant, so you can route them wherever you like instead of living in the TalkingPoints app.

It keeps one logged-in browser alive, watches the messages the web app fetches, and POSTs new ones to a Home Assistant webhook.

Why a whole browser?

TalkingPoints' web app authenticates every API call with an x-token header that is the raw Meteor login token. That token lives only in the app's in-memory JavaScript: it is never in a response body, never written to disk, and injected by in-app code. So it cannot be extracted and replayed from a script. Consequences:

  • A fresh process / page reload starts logged out (in-memory session).
  • The only way to make authenticated calls is to keep the real logged-in app running and intercept the /inbox responses it already makes.

Hence: one persistent, headed Chromium (under Xvfb), logged in via noVNC.

What it reads

GET /api/parents/v3/inbox returns, per conversation: teacher (with.user), student (with.student), lastMessageId, lastMessageDate, lastMessage (preview), and unreadCount. The poller tracks lastMessageId per conversation and forwards on change. The app self-polls /inbox, so detection is near real-time.

Webhook payload:

{ "source": "talkingpoints", "event": "message", "from": "Teacher Name",
  "student": "Kid Name", "preview": "", "unread": 1,
  "at": "2026-07-13T12:32:39.596Z", "conversationId": "" }

A {"event":"session_expired"} payload is sent if the login drops, so you can alert yourself to re-auth.

Local development (Colima / Docker Desktop)

npm install
npx playwright install chromium
node ha-mock.mjs &                 # stand-in HA receiver on :8123
FORWARD_ON_START=1 node poller.mjs # headed browser; log in + open your inbox

FORWARD_ON_START=1 forwards the current latest message per conversation once, to prove the pipe. Leave it off in production.

Deploy on a NAS (QNAP Container Station, docker compose)

  1. Create a Home Assistant webhook automation trigger and copy its URL.
  2. cp .env.example .env and set HA_WEBHOOK_URL.
  3. Build + start on the NAS (native amd64):
    docker compose up -d --build
  4. Open noVNC on the LAN only: http://<nas>:6080/vnc.html, then log in in the Chromium window (phone number → SMS code) and open your inbox.
  5. Done. It forwards new messages to HA and survives restarts (seen-state is persisted in ./data).

Re-authentication

The session is in-memory, so it does not survive a container restart, and may expire on its own after a while. When it drops, the poller sends a session_expired webhook. To recover, open noVNC and log in again in the same running container — no rebuild needed.

Security

  • data/ (session, tokens, message content) and .env are gitignored. Never commit them.
  • The noVNC port is a live, authenticated view of your child's school messages. Bind it to LAN/VPN only (Tailscale, or the NAS reverse proxy with auth). Do not expose it to the internet.

Files

File Purpose
poller.mjs Keep-alive browser, intercepts /inbox, forwards to HA
ha-mock.mjs Local stand-in for the HA webhook (dev only)
Dockerfile / entrypoint.sh Headed Chromium + Xvfb + noVNC
docker-compose.yml NAS deployment
login.mjs, capture*.mjs, probe.mjs, … Discovery/reverse-engineering scripts kept for reference

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages