# Home Assistant automation notification notifications on your phone

> Get a push notification from any Home Assistant automation or script, with your own title, message, priority and link, sent through a rest_command.

- Company: Home Assistant (https://www.justpush.io/recipes/home-assistant)
- Event: `rest_command` (rest_command)
- Tags: Smart home, Home automation
- Install: https://studio.justpush.io/recipes/home-assistant/automation-notification
- Web page: https://www.justpush.io/recipes/home-assistant/automation-notification

## Setup

1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL.
2. Home Assistant has no outgoing webhooks, so add a rest_command to your configuration.yaml that posts JSON to your webhook URL (shown in Studio after install).
3. Restart Home Assistant (or reload YAML) so the rest_command action appears.
4. Call that action from an automation or script, as shown in the recipe's instructions.
5. Home Assistant has no outgoing webhooks, so you send the push yourself with a **RESTful Command** (`rest_command`). The simplest version has a fixed message. Add this to `configuration.yaml`:
6. ```yaml
7. rest_command:
8. justpush_front_door:
9. url: "your webhook URL (shown in Studio after install)"
10. method: post
11. content_type: "application/json"
12. payload: '{"title": "🚪 Front door opened", "message": "Someone opened the front door", "priority": 1}'
13. ```
14. Restart Home Assistant (or reload YAML under **Developer tools → YAML**), then add the action **RESTful Command: justpush_front_door** to any automation, for example one with a state trigger on your door sensor turning on. You can try it straight away from **Developer tools → Actions**.
15. The body accepts `title`, `message`, `priority` (-2 to 2, or `low`, `normal`, `high`, `highest`), `url` (adds an **Open** button, with an optional `button` label), `entity_id`, `state` and `topic`. There must be a title or a message; values such as `unknown`, `unavailable` or `None` are ignored.
16. **One reusable command for every automation.** To pass the title and message from each automation (for example "washing machine done", with the energy it used), the payload needs Home Assistant templates. Those examples are in this recipe's README on GitHub: https://github.com/JustPush-io/studio-recipes/tree/main/home-assistant/automation-notification
17. Add `?ha=` with your Home Assistant address to the URL (e.g. `your webhook URL (shown in Studio after install)?ha=https://homeassistant.local:8123`) and pushes that include an `entity_id` get a **View history** button.
18. Requests aren't signed, so keep your endpoint URL private (put it in `secrets.yaml` if you share your configuration).

## Code

Studio calls `handleRequest(request)` with the incoming webhook (`{ method, headers, body, query, raw }`) and sends the message object it returns. Returning `null` sends nothing.

```js
// Home Assistant → automation notification (rest_command)
// Fires when a Home Assistant automation or script calls a rest_command that posts a small JSON
// body to this integration: {"title", "message", "priority", "url", "entity_id", "state", "topic"}.
// Docs: https://www.home-assistant.io/integrations/rest_command/
//
// Home Assistant has no outgoing webhooks of its own, so you define the body yourself. Every field
// is optional except that there must be a title or a message. Values that Home Assistant templates
// render when something is missing ("None", "unknown", "unavailable", "") are ignored.

// What Home Assistant templates render when a value is missing. Treated as "not given".
const MISSING = new Set(["", "none", "null", "unknown", "unavailable", "undefined", "nan"])

// A trimmed, non-missing string (numbers are turned into text), or null.
function clean(value, max = 250) {
    if (typeof value === "number") return Number.isFinite(value) ? String(value) : null
    if (typeof value === "boolean") return String(value)
    if (typeof value !== "string") return null

    const text = value.trim()
    if (MISSING.has(text.toLowerCase())) return null
    return text.length > max ? `${text.slice(0, max - 1)}…` : text
}

// Table lookup that ignores inherited names such as "toString".
function pick(table, key, fallback) {
    return typeof key === "string" && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback
}

// Only link to real http(s) URLs.
function link(url, cta) {
    return typeof url === "string" && /^https?:\/\//.test(url) ? [{ cta, url }] : []
}

// Priority as a number (-2…2), a numeric string, or a word such as "high".
const PRIORITY_WORDS = {
    lowest: -2,
    low: -1,
    normal: 0,
    default: 0,
    high: 1,
    highest: 2,
    urgent: 2,
    critical: 2,
    emergency: 2,
}

function priority(value, fallback) {
    const clamp = (n) => Math.max(-2, Math.min(2, Math.round(n)))
    if (typeof value === "number") return Number.isFinite(value) ? clamp(value) : fallback

    const text = clean(value)
    if (!text) return fallback
    if (/^[+-]?\d+(\.\d+)?$/.test(text)) return clamp(Number(text))
    return pick(PRIORITY_WORDS, text.toLowerCase(), fallback)
}

// Entity IDs look like "binary_sensor.front_door".
function entityId(value) {
    const text = clean(value)
    return text && /^[a-z0-9_]+\.[a-z0-9_]+$/.test(text) ? text : null
}

// The request body as an object. A rest_command without content_type: application/json
// may arrive as a JSON string, so that's parsed too.
function bodyOf(request) {
    let body = request.body
    if (typeof body === "string" && body.trim().startsWith("{")) {
        try {
            body = JSON.parse(body)
        } catch {
            return {}
        }
    }
    return body && typeof body === "object" && !Array.isArray(body) ? body : {}
}

// ?ha=https://homeassistant.local:8123 adds a button to the entity's history.
function historyButton(request, entity) {
    const base = clean(request.query?.ha, 200)
    if (!entity || !base || !/^https?:\/\/[^\s]+$/.test(base)) return []
    return link(`${base.replace(/\/+$/, "")}/history?entity_id=${encodeURIComponent(entity)}`, "View history")
}

function handleRequest(request) {
    const body = bodyOf(request)

    // State-change bodies (with to_state) belong to the state-change recipe.
    if (Object.prototype.hasOwnProperty.call(body, "to_state")) {
        console.log("Ignoring state-change body — use the state-change recipe")
        return null
    }

    const entity = entityId(body.entity_id)
    const state = clean(body.state, 100)
    let title = clean(body.title, 120)
    let message = clean(body.message, 1000)

    // Guard: nothing to say. (An entity and state alone still make a message.)
    if (!title && !message && !(entity && state)) {
        console.log("Ignoring Home Assistant request without a title or message")
        return null
    }

    if (!message && entity && state) message = `${entity} is ${state}`
    if (!title) title = "Home Assistant"

    const button = clean(body.button, 30) ?? "Open"

    return {
        title,
        message: message ?? "",
        topic: clean(body.topic, 50) ?? "Home Assistant",
        // Normal (0) unless the automation asks for something else; the automation knows best.
        priority: priority(body.priority, 0),
        buttons: [...link(clean(body.url, 500), button), ...historyButton(request, entity)],
    }
}
```

## Home Assistant rest_command webhook payload (sample)

```json
{
  "url": "",
  "state": "1.8",
  "title": "🧺 Washing machine done",
  "message": "Time to empty it. This wash used 0.9 kWh.",
  "priority": "0",
  "entity_id": "sensor.washing_machine_power"
}
```

## FAQ

### Does this work on iPhone and Android?

Yes. Install the JustPush app from the App Store or Google Play and sign in. Every phone signed in to your account gets the notification.

### Do I need to write code?

No. Install the recipe in Studio, paste your webhook URL into Home Assistant and you are done. The code is there if you want to change the text, the sound or the buttons.

### Can I change what the notification says?

Yes. After install the recipe's code is yours. Edit it in Studio and test it against the sample payload before you save.

### What does it cost?

JustPush is free for 30 days. After that it's $19.99 a year, or $39.99 once. There is no extra charge for recipes.
