this post was submitted on 14 Mar 2024
72 points (98.6% liked)

homeassistant

12111 readers
84 users here now

Home Assistant is open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts. Perfect to run on a Raspberry Pi or a local server. Available for free at home-assistant.io

founded 1 year ago
MODERATORS
 

I just got a large batch of water leak sensors and was setting an automation to send a notification to my phone and I was worried that I would miss the notification. I found this page in the documentation for doing critical alerts. On iOS the notification stays persistent, even after unlocking the device. What’s really nice is that if you have an Apple Watch, the notification will also show up there and play a sound if the watch is on silent mode.

Even though I hope I never get one of these notifications, I’m really glad that this functionality exists within Home Assistant.

Just thought that was really neat.

top 8 comments
sorted by: hot top controversial new old
[–] [email protected] 13 points 8 months ago (2 children)

I do the same (except on Android instead of iOS) and it works great. I have the alerts go to all our TVs (via our Nvidia Shield boxes and https://www.home-assistant.io/integrations/nfandroidtv/) and Google speakers too.

Recently had one of the leak detectors detect a leak and the alerting worked great. Turns out the leak was a bottle of distilled water dripping out the back of the bottle.

[–] [email protected] 5 points 8 months ago (1 children)

I did not know that you could send notifications to an Nvidia Shield. I’ll have to look into that this evening. Thanks!

[–] [email protected] 3 points 8 months ago* (last edited 8 months ago) (1 children)

It works well, and the TV app is free: https://play.google.com/store/apps/details?id=de.cyberdream.androidtv.notifications.google&hl=en_US&gl=US, you just need to download it from the Play Store on the Shield. There's a companion app for phones that costs money, but you don't need that one - it's only for sending messages from your phone to the TV.

[–] [email protected] 1 points 8 months ago

Set it up last night. Can confirm it was quick and easy. Thanks!

[–] [email protected] 1 points 8 months ago (1 children)

I've struggled with getting my TV notifications to show an image because I can't seem to get the URLs right. Is that an issue you've had? Any ideas on a solution?

[–] [email protected] 2 points 8 months ago* (last edited 8 months ago)

Put the image in the media directory in your Home Assistant config directory then use /media/.... as the URL. This works for me.

For my security cameras, I have a Node-RED flow:

It:

  • Listens for MQTT events from Blue Iris
  • Builds a message based on the AI detection result and camera name (e.g. "Person detected at Front")
  • Write image file from MQTT event to media/alerts/ directory
  • Send notification to phones and TV (currently just goes to one Shield - I need to set up the second one eventually)
  • If a person is detected, send notification to Google speakers

Here's the JSON for the flow:

JSON

[
    {
        "id": "329ba4b7632a95c8",
        "type": "tab",
        "label": "Camera",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "f64fc2c05427d1ff",
        "type": "mqtt in",
        "z": "329ba4b7632a95c8",
        "name": "BlueIris/+/alert-image-b64",
        "topic": "BlueIris/+/alert-image-b64",
        "qos": "2",
        "datatype": "json",
        "broker": "e811c8eb637d26a5",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 130,
        "y": 40,
        "wires": [
            [
                "5d5d6c7623201f34"
            ]
        ]
    },
    {
        "id": "5d5d6c7623201f34",
        "type": "function",
        "z": "329ba4b7632a95c8",
        "name": "Process payload and build message",
        "func": "const {img, ...otherPayloadFields} = msg.payload;\n// TODO: Filter these out in Blue Iris AI config\nconst objectsToFilter = new Set([\n    'ball',\n    'sports ball',\n    'horse',\n    'book',\n    'suitcase',\n]);\n\nlet formattedObjectNames = 'Nothing';\nconst objectsData = (otherPayloadFields.json || [])\n    .find(x => x.api === 'objects');\n// Would normally use `objectData?.found?.success` but Node-RED doesn't support it\nconst hasObjects = objectsData && objectsData.found && objectsData.found.success;\nif (hasObjects) {\n    // Using Array.from(new Set(...)) to dedupe object names\n    const objectNames = Array.from(new Set(\n        (objectsData.found.predictions || [])\n            .sort(x => -x.confidence)\n            .map(x => x.label)\n            .filter(x => !objectsToFilter.has(x))\n    ));\n    if (objectNames.length > 0) {\n        // Capitalise first letter of first object\n        objectNames[0] = objectNames[0][0].toUpperCase() + objectNames[0].substring(1)\n       formattedObjectNames = objectNames.join(' and ');\n    }\n}\n\nconst message = formattedObjectNames + ' detected at ' + otherPayloadFields.name;\nreturn {\n    image_filename: Date.now() + '-' + otherPayloadFields.id + '.jpg',\n    message,\n    object_names: formattedObjectNames,\n    payload: Buffer.from(img, 'base64'),\n    original_payload: otherPayloadFields,\n};",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 430,
        "y": 40,
        "wires": [
            [
                "31138938746cf6fd",
                "53f4a59537f2893e"
            ]
        ]
    },
    {
        "id": "31138938746cf6fd",
        "type": "file",
        "z": "329ba4b7632a95c8",
        "name": "write image file",
        "filename": "\"/media/alerts/\" & image_filename",
        "filenameType": "jsonata",
        "appendNewline": false,
        "createDir": false,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 700,
        "y": 40,
        "wires": [
            [
                "6490fa5f55043f2a",
                "1ca18fe555c917fa"
            ]
        ]
    },
    {
        "id": "6490fa5f55043f2a",
        "type": "api-call-service",
        "z": "329ba4b7632a95c8",
        "name": "Notify phones",
        "server": "b6f128b45d1d76f7",
        "version": 5,
        "debugenabled": false,
        "domain": "notify",
        "service": "all_phones",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\t   \"message\": message,\t   \"data\": {\t        \"clickAction\": \"http://cameras.vpn.d.sb:81/ui3.htm?maximize=1&tab=alerts&cam=\" & original_payload.camera & \"&rec=\" & original_payload.id,\t        \"image\": \"/media/local/alerts/\" & image_filename,\t        \"actions\": [{\t            \"action\": \"URI\",\t            \"title\": \"Live View\",\t            \"uri\": \"http://cameras.vpn.d.sb:81/ui3.htm?maximize=1&cam=\" & original_payload.camera\t        }, {\t            \"action\": \"URI\",\t            \"title\": \"View Clip\",\t            \"uri\": \"http://cameras.vpn.d.sb:81/ui3.htm?maximize=1&tab=alerts&cam=\" & original_payload.camera & \"&rec=\" & original_payload.id\t        }],\t       \t        \"channel\": \"Camera\",\t        \"ttl\": 0,\t        \"priority\": \"high\",\t        \"importance\": \"high\"\t    }\t}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 900,
        "y": 40,
        "wires": [
            []
        ]
    },
    {
        "id": "1ca18fe555c917fa",
        "type": "api-call-service",
        "z": "329ba4b7632a95c8",
        "name": "Notify TV",
        "server": "b6f128b45d1d76f7",
        "version": 5,
        "debugenabled": false,
        "domain": "notify",
        "service": "shield",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\t   \"message\": message,\t   \"data\": {\t        \"image\": {\t            \"path\": \"/media/alerts/\" & image_filename\t        }\t    }\t}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 880,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "53f4a59537f2893e",
        "type": "switch",
        "z": "329ba4b7632a95c8",
        "name": "Is person?",
        "property": "message",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "person",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "Person",
                "vt": "str"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 710,
        "y": 160,
        "wires": [
            [
                "31ec03e4d62909c3"
            ],
            [
                "31ec03e4d62909c3"
            ]
        ]
    },
    {
        "id": "31ec03e4d62909c3",
        "type": "api-call-service",
        "z": "329ba4b7632a95c8",
        "name": "Notify Google Speakers",
        "server": "b6f128b45d1d76f7",
        "version": 3,
        "debugenabled": false,
        "service": "google_assistant_sdk",
        "entityId": "",
        "data": "{\"message\": message}",
        "dataType": "jsonata",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "service_domain": "notify",
        "mergecontext": "",
        "x": 930,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "e811c8eb637d26a5",
        "type": "mqtt-broker",
        "name": "MQTT",
        "broker": "mqtt.int.d.sb",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "b6f128b45d1d76f7",
        "type": "server",
        "name": "Home Assistant",
        "version": 2,
        "addon": false,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30"
    }
]

[–] [email protected] 2 points 8 months ago

I have done this for my leak detectors.
Almost everything else obeys DND, but water? That's gonna wake me up.

[–] GlitzyArmrest 1 points 8 months ago

At least on Android, you can make TTS go through your alarm channel on your phone at max volume, to really make sure you don't miss it. I do this for my alarm and doorbell (only when I'm at home).