PiPup listens on a small HTTP server on your TV. Anything on your network can trigger a notification with a single request — from curl, a script, or Home Assistant. Here are copy-paste examples for both.
192.168.1.50:7979) and a QR code. All requests go to http://<tv-ip>:7979.Authorization: Bearer <token> header to every request.Tip: replace <tv-ip> with your TV's IP in the examples below. Test reachability first with curl http://<tv-ip>:7979/ping — it should reply pipup <version>.
Every example is a plain HTTP call — use them from curl, a shell script, Node, Python, or any HTTP client. The body is JSON unless noted.
Check the server is up and read a JSON status snapshot (version, active popups, uptime).
# plain-text reachability check curl http://<tv-ip>:7979/ping # JSON status curl http://<tv-ip>:7979/status
Title, message, and how long it stays on screen (seconds).
curl -X POST http://<tv-ip>:7979/notify \
-H "Content-Type: application/json" \
-d '{"title": "Hello", "message": "PiPup is working", "duration": 10}'Embed a still image — e.g. a camera snapshot URL. It also accepts an inline data: base64 URI.
curl -X POST http://<tv-ip>:7979/notify \
-H "Content-Type: application/json" \
-d '{
"title": "Front door",
"message": "Motion detected",
"duration": 15,
"media": { "image": { "uri": "http://<camera>/snapshot.jpg", "width": 640 } }
}'Embed a live stream. The most compatible source is an HTTP-MP4 URL from go2rtc (bundled with Home Assistant); plain rtsp:// and HLS also work.
curl -X POST http://<tv-ip>:7979/notify \
-H "Content-Type: application/json" \
-d '{
"title": "Doorbell",
"duration": 20,
"media": { "video": { "uri": "http://<go2rtc-host>:1984/api/stream.mp4?src=doorbell", "width": 760 } }
}'Note: encrypted rtsps:// (RTSP over TLS / SRTP) is not supported by the player — this affects UniFi Protect's default stream. Restream it through go2rtc (recommended) or enable a plain rtsp:// stream on the camera.
Add tts to speak the notification aloud. Use it with or without an on-screen message.
curl -X POST http://<tv-ip>:7979/notify \
-H "Content-Type: application/json" \
-d '{"message": "The laundry is done", "tts": "The laundry is done", "duration": 8}'Colors use #[AA]RRGGBB. Add rounded corners, a border, and a progress bar that drains over duration.
curl -X POST http://<tv-ip>:7979/notify \
-H "Content-Type: application/json" \
-d '{
"title": "Weather alert",
"message": "Severe thunderstorm warning",
"duration": 12,
"position": 0,
"backgroundColor": "#CC161616",
"titleColor": "#FBBF24",
"cornerRadius": 18,
"borderColor": "#FBBF24",
"borderWidth": 2,
"showProgress": true
}'position: 0 top-right · 1 top-left · 2 bottom-right · 3 bottom-left · 4 center. Set "duration": 0 to keep a popup on screen until you dismiss it.
/notify returns {"status":"ok","id":"…"}. Dismiss everything, or just one popup by its id.
# dismiss all popups curl -X POST http://<tv-ip>:7979/cancel # dismiss a single popup by the id /notify returned curl -X POST "http://<tv-ip>:7979/cancel?id=<id>"
Use multipart/form-data to upload an image from disk instead of a URL.
curl -X POST http://<tv-ip>:7979/notify \ -F "title=Snapshot" \ -F "duration=15" \ -F "image=@/path/to/snapshot.jpg"
If a token is configured, send it as a bearer header (or ?token= query parameter).
curl -X POST http://<tv-ip>:7979/notify \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-d '{"title": "Secure", "message": "Authenticated request"}'Wrap PiPup in a rest_command, then call it from any automation or script. Add the IP of your TV; templated fields let one command serve many alerts.
Prefer a native integration? The PiPup Home Assistant integration (HACS) auto-discovers your TVs over mDNS and adds a proper notify.send_message / pipup.send service and a per-TV status sensor — no IPs or rest_command to maintain. The examples below are the no-install alternative.
In configuration.yaml (restart HA after adding it):
# configuration.yaml rest_command: pipup: url: "http://<tv-ip>:7979/notify" method: POST content_type: "application/json" # uncomment only if you set a token in PiPup: # headers: # authorization: "Bearer <your-token>" payload: >- {"title": "{{ title }}", "message": "{{ message }}", "duration": {{ duration | default(15) }}}
Show a notification when the doorbell is pressed:
automation:
- alias: "Doorbell → TV"
trigger:
- platform: state
entity_id: binary_sensor.front_doorbell
to: "on"
action:
- service: rest_command.pipup
data:
title: "Front door"
message: "Someone is at the door"A dedicated command that embeds the go2rtc HTTP-MP4 stream (works even when the camera's native stream is rtsps://):
rest_command:
pipup_doorbell:
url: "http://<tv-ip>:7979/notify"
method: POST
content_type: "application/json"
payload: >-
{"title": "Front door", "message": "Someone is at the door", "duration": 20,
"media": {"video": {"uri": "http://<go2rtc-host>:1984/api/stream.mp4?src=doorbell", "width": 760}}}Speak an alert aloud — great for "laundry done" or "garage left open":
rest_command:
pipup_say:
url: "http://<tv-ip>:7979/notify"
method: POST
content_type: "application/json"
payload: >-
{"message": "{{ message }}", "tts": "{{ message }}", "duration": 8}# …then in an automation:
- service: rest_command.pipup_say
data:
message: "The washing machine has finished"More fields — beyond the examples above, a notification also supports a leading iconUri, a sound to play, borders (borderColor + borderWidth), cornerRadius, media placement (mediaPosition), title/message alignment, entrance/exit animations, and shown/dismissed callback URLs. Add any of them to the JSON body.
Install PiPup on your Android TV, open it once to grant the display permission, and send your first request.