Home Assistant integration for Mast, a pager app for iPhone and Android.
It adds a mast.page action that sends a message and then waits for a person to acknowledge it
before the automation carries on. That covers the automations a normal notification can't: a leak
sensor has gone wet and the main valve is about to close, a delivery is at the door and the lock is
about to open. The action returns whether anybody answered, which device answered, and how long
they took.
Home Assistant reads the acknowledgement by polling Mast on a connection it opened itself, so none of this needs your instance to be reachable from the internet. The heartbeat runs the other way: if Home Assistant stops checking in, Mast pages you, which is the one alarm your instance can't raise for itself.
Mast Pager is free on the App Store and Google Play, with no account needed and no per-message charge. iPhone with iOS 17.2 or later, or Android 12 or later.
- Home Assistant 2025.8.0 or newer
- The Mast app, with at least one channel set up
Add this repository as a custom repository with category Integration:
https://github.com/tissue-systems/hass-mast
Download it, then restart Home Assistant.
Copy custom_components/mast into <config>/custom_components/mast, where <config> is your
Home Assistant configuration directory, and restart.
Go to Settings → Devices & Services → Add Integration → Mast, or use the button:
In the Mast app, open Channels, tap a channel and copy its URL. Paste it into the form. Anything holding that URL can page the phone, so treat it like a password.
Setting up doesn't send a test page. The integration asks Mast about a message id that can't exist, and the two different "not found" answers say whether the key resolves. Your phone stays quiet.
Each channel becomes a device, and the name you give it is what the entity ids are built from. Add the integration again for a second phone.
If you ever hit Disconnect in the Mast app, every channel key is re-minted. Use Reconfigure on the integration and paste the new URL; entities and automations are unaffected.
| Key | Default | Description |
|---|---|---|
| Heartbeat | off | Send a beat to this channel on a timer. Only useful on a channel set to Vital in the app. |
| Heartbeat interval | 5 min | How often to beat. Set the channel's grace period in the app a little longer than this. |
| Action | Description |
|---|---|
mast.send |
Send a message at one of four priorities. |
mast.page |
Send at page priority and wait for somebody to acknowledge it. |
mast.resolve |
Close an open page because the condition cleared. |
mast.ping |
Send one heartbeat to a vital channel. |
mast.status |
Look up what happened to one message. |
mast.send and mast.page take the same fields, except for the last four:
| Field | Default | Description |
|---|---|---|
config_entry_id |
the only channel | Which channel to use. Needed once you have more than one. |
title |
The line on the lock screen. | |
body |
The rest of the message. One of title or body is required. |
|
priority |
normal, or page for mast.page |
quiet, normal, loud or page. Only page repeats and only page sounds with the ringer switch off. |
url |
An https link the notification opens. |
|
url_title |
The label on that link. | |
key |
Deduplication key. Messages sharing a key fold onto one card, and this is what mast.resolve closes. |
|
sound |
Alert sound to use. | |
retry |
Seconds between re-alerts while a page goes unanswered. | |
expire |
Stop repeating after this many seconds, answered or not. | |
ack (mast.send) |
false |
Ask for an acknowledgement without waiting for it. The answer arrives as an event. |
silent (mast.send) |
false |
Deliver without a sound, whatever the priority. |
wait_for_ack (mast.page) |
true |
Hold the automation until somebody answers or the timeout passes. |
timeout (mast.page) |
300 |
Seconds to wait. |
mast.page fills a response_variable with:
| Field | Description |
|---|---|
id |
The Mast message id. |
state |
What Mast last said about the message. |
acknowledged |
true if somebody answered in time. |
timed_out |
true if the wait ran out. The page is still open on the phone. |
waited |
false when wait_for_ack was off, or when Mast suppressed the page (quiet hours, for instance) and so no answer was ever coming. |
acked_by |
The device that answered. Only present once somebody has. |
acked_at, open_for |
When it was answered, and how many seconds it was open. Mast measures open_for, so it doesn't depend on this machine's clock. |
mast.resolve needs either a key or a message_id, and returns open_for for the incident it
closed. mast.status takes a message_id and returns Mast's record of it.
Each channel gets these, named after the channel:
| Entity | Description |
|---|---|
notify.<channel> |
The plain notify entity, for anything that just needs a line of text. |
binary_sensor.<channel>_page_open |
On while a page is waiting for an answer. Drive a siren off this directly; it goes off the moment somebody acknowledges. |
sensor.<channel>_open_pages |
How many pages are open. |
sensor.<channel>_last_acknowledged_by |
Which device answered last. |
sensor.<channel>_last_time_to_acknowledge |
Seconds the last page waited. It is a measurement, so long-term statistics keep the average time it takes your household to answer. |
event.<channel>_answer |
Fires on acknowledged, resolved and expired. |
The same three also land on the bus as mast_acknowledged, mast_resolved and mast_expired,
carrying channel, message_id, title, key, acked_by and open_for.
Four blueprints are in blueprints/automation/mast/. Import them with the buttons below, or copy
the files into <config>/blueprints/automation/mast/.
actions:
- action: mast.page
data:
title: "Unlock the front door?"
body: "A delivery is at the door and nobody is home."
timeout: 120
response_variable: answer
- if: "{{ answer.acknowledged }}"
then:
- action: lock.unlock
target: { entity_id: lock.front_door }Say in the body what happens if they don't answer. That is the part they read on the lock screen.
actions:
- action: mast.page
data:
title: "Water in the basement"
body: "Closing the main valve in 2 minutes unless you acknowledge this."
key: "leak-basement"
priority: page
retry: 30
timeout: 120
response_variable: answer
- if: "{{ not answer.acknowledged }}"
then:
- action: switch.turn_off
target: { entity_id: switch.main_valve }If the sensor clears while you're still driving home, mast.resolve turns the card on the phone
green and puts the incident duration on it, instead of sending a second notification saying never
mind.
actions:
- action: mast.resolve
data:
key: "leak-basement"
title: "The basement is dry"
response_variable: closedkey is what gives an incident an identity. Using key: "{{ trigger.entity_id }}" folds forty
re-triggers of one flapping sensor onto a single card with a count on it, and mast.resolve
closes that one card.
Turn the heartbeat on in the integration's options and set the channel to Vital in the Mast app, with a grace period a little longer than the interval. When the instance stops beating, because the power went out or the SD card died or an upgrade went wrong, Mast pages you. No automation running inside the house can do that.
- A timeout is not a cancellation.
mast.pagereturningtimed_out: trueleaves the page open on the phone. If somebody answers ten minutes later,event.<channel>_answerstill fires and anything triggered off it still runs. - There's no
mast.ackaction. An acknowledgement is supposed to mean a person looked at the page, and an action that let Home Assistant acknowledge by itself would defeat that. Usemast.resolvewhen the condition clears on its own. urlhas to behttps. Ahomeassistant://deep link is rejected. Use ahttps://my.home-assistant.io/redirect/entity/?entity_id=...link instead: it passes the check, and it opens the companion app on the right screen.- Mast allows 60 requests a minute per channel, shared between sends and the polling that reads acknowledgements. The integration spends at most half of that on polling, polls a page less often the longer it stays open, and when several are open at once keeps polling the oldest first.
- Diagnostics never carry the channel key. It is truncated to its first few characters there.
- Mast - the app, the four priority levels and vital channels.
- Mast and Home Assistant - the same automations
written with
rest_command, if you'd rather not install a custom component.
MIT, see LICENSE.