Skip to content

Commit

Permalink
docs: Add actionalble notification subflow to cookbook
Browse files Browse the repository at this point in the history
  • Loading branch information
zachowj committed Dec 19, 2020
1 parent 437a32f commit 51ad8f2
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module.exports = {
'check-if-an-entity-was-turned-on-in-the-last-24-hours',
'starting-flow-after-home-assistant-restart',
'holiday-lights-scheduler-and-demo-mode-for-wled',
'actionable-notifications-subflow-for-android',
],
},
],
Expand Down
1 change: 1 addition & 0 deletions docs/cookbook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ further educate yourself in the world of Home Automation with Node-RED.
- [Check if an entity was a certain state in the last 24 hours](./check-if-an-entity-was-turned-on-in-the-last-24-hours.md)
- [Starting flow after Home Assistant reestart](./starting-flow-after-home-assistant-restart.md)
- [Holiday lights scheduler and demo mode for WLED](./holiday-lights-scheduler-and-demo-mode-for-wled.md)
- [Actionable Notifications Subflow for Android](./actionable-notifications-subflow-for-android.md)

All JSON exports are also available under the examples tab in the Node-RED
import menu.
Expand Down
31 changes: 31 additions & 0 deletions docs/cookbook/actionable-notifications-subflow-for-android.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Actionable Notifications Subflow for Android

![screenshot](./images/actionable-notifications-subflow-for-android_01.png)

<<< @/examples/cookbook/actionable-notifications-subflow-for-android/subflow.json

| Options | Description | Documentation |
| -------------- | ------------------------------------------------------------------------------------------------------ | :-----------------------------------------------------------------------------------------------------------------------------------: |
| Notify Service | Can take multiple services as a comma delimited list e.g.: `mobile_app_username, mobile_app_username2` | |
| Title | Top line of text | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic) |
| Message | Second line of text accepts HTML tags | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-message-html-formatting) |
| Action Title | The button title | [link](https://companion.home-assistant.io/docs/notifications/actionable-notifications#building-automations-for-notification-actions) |
| Action URI | lovelace dashboard, `https://` or `app://`. If URI is defined no action is returned to Node-RED | [link](https://companion.home-assistant.io/docs/notifications/actionable-notifications#building-automations-for-notification-actions) |
| User Info | Will resolve user info in Node-RED and place it in `msg.userData` | |
| Sticky | Set whether to dismiss the notification upon selecting it or not | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#sticky-notification) |
| Group | string | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#thread-id-grouping-notifications) |
| Color | Color name or the hex code | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-color) |
| Timeout | How long a notification will be shown on a users device before being removed automatically | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-timeout) |
| Icon | Path to icon | [link](https://companion.home-assistant.io/docs/notifications/notifications-basic#notification-icon) |

## Demo flow

![screenshot](./images/actionable-notifications-subflow-for-android_02.png)

<<< @/examples/cookbook/actionable-notifications-subflow-for-android/demo.json

## Use Case #1: Get notification when garage door is left open with ability to ignore the alert for an amount of time

![screenshot](./images/actionable-notifications-subflow-for-android_03.png)

<<< @/examples/cookbook/actionable-notifications-subflow-for-android/use-case-01.json
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"id":"6dc0247c.d7210c","type":"subflow","name":"Actionable Notification","info":"[Documentation](https://zachowj.github.io/node-red-contrib-home-assistant-websocket/cookbook/actionable-notifications-subflow-for-android.html)\n","category":"","in":[{"x":84,"y":80,"wires":[{"id":"9d85d137.fe487"}]}],"out":[{"x":1172,"y":128,"wires":[{"id":"974bd48d.c253e8","port":0}]},{"x":1172,"y":176,"wires":[{"id":"974bd48d.c253e8","port":1}]},{"x":1172,"y":224,"wires":[{"id":"974bd48d.c253e8","port":2}]},{"x":964,"y":240,"wires":[{"id":"5bc7345c.07b1cc","port":1}]}],"env":[{"name":"service","type":"str","value":"","ui":{"label":{"en-US":"Notify Service"},"type":"input","opts":{"types":["str"]}}},{"name":"title","type":"str","value":"","ui":{"label":{"en-US":"Title"},"type":"input","opts":{"types":["str"]}}},{"name":"message","type":"str","value":"","ui":{"label":{"en-US":"Message"},"type":"input","opts":{"types":["str"]}}},{"name":"action1Title","type":"str","value":"","ui":{"label":{"en-US":"Action 1 Title"},"type":"input","opts":{"types":["str"]}}},{"name":"action1Uri","type":"str","value":"","ui":{"label":{"en-US":"Action 1 URI (optional)"},"type":"input","opts":{"types":["str"]}}},{"name":"action2Title","type":"str","value":"","ui":{"label":{"en-US":"Action 2 Title"},"type":"input","opts":{"types":["str"]}}},{"name":"action2Uri","type":"str","value":"","ui":{"label":{"en-US":"Action 2 URI (optional)"},"type":"input","opts":{"types":["str"]}}},{"name":"action3Title","type":"str","value":"","ui":{"label":{"en-US":"Action 3 Title"},"type":"input","opts":{"types":["str"]}}},{"name":"action3Uri","type":"str","value":"","ui":{"label":{"en-US":"Action 3 URI (optional)"},"type":"input","opts":{"types":["str"]}}},{"name":"userInfo","type":"bool","value":"false","ui":{"label":{"en-US":"Populate User Information"},"type":"checkbox"}},{"name":"sticky","type":"bool","value":"false","ui":{"label":{"en-US":"Sticky"},"type":"checkbox"}},{"name":"group","type":"str","value":"None","ui":{"label":{"en-US":"Group"},"type":"select","opts":{"opts":[{"l":{"en-US":"None"},"v":""},{"l":{"en-US":"Cameras"},"v":"camera"},{"l":{"en-US":"Security"},"v":"security"},{"l":{"en-US":"Garage"},"v":"garage"},{"l":{"en-US":"Laundry Room"},"v":"laundry_room"}]}}},{"name":"color","type":"str","value":"","ui":{"label":{"en-US":"Color"},"type":"input","opts":{"types":["str"]}}},{"name":"timeout","type":"num","value":"","ui":{"label":{"en-US":"Timeout"},"type":"input","opts":{"types":["num"]}}},{"name":"icon","type":"str","value":"","ui":{"label":{"en-US":"Icon"},"type":"input","opts":{"types":["str"]}}}],"color":"#DDAA99","outputLabels":["Action 1","Action 2","Action 3","Cleared"],"status":{"x":244,"y":272,"wires":[{"id":"204dbcfc.144ae4","port":0}]}},{"id":"f9e57204.71076","type":"function","z":"6dc0247c.d7210c","name":"create service call","func":"const actions = [];\n[1,2,3].forEach(i => {\n const name = `action${i}`\n const id = flow.get(`${name}Id`);\n const title = env.get(`${name}Title`);\n const uri = env.get(`${name}Uri`);\n const action = !!uri.length ? 'URI' : title ? flow.get(`${name}Id`) : undefined;\n \n actions.push({\n action,\n title,\n uri\n });\n});\n\nmsg._originalPayload = msg.payload;\nflow.set('latestMessage', msg);\n\nconst services = env.get('service');\nif(!services) {\n node.status({\n text: 'no services defined',\n shape: 'ring',\n fill: 'red'\n });\n return; \n}\n\nservices.trim().split(/,\\s*/).forEach(service => {\n if(!service) return;\n \n msg.payload = {\n service,\n data: {\n title: env.get('title'),\n message: env.get('message'),\n data: {\n tag: flow.get('notificationTag'),\n actions,\n color: env.get(\"color\"),\n group: env.get(\"group\"),\n sticky: env.get(\"sticky\"),\n timeout: env.get(\"timeout\"),\n icon: env.get(\"icon\")\n }\n }\n };\n node.send(msg);\n});\n\nnode.done();","outputs":1,"noerr":0,"initialize":"const randomId = () => Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);\n\n[1,2,3].forEach(i => {\n flow.set(`action${i}Id`, `action${i}_${randomId()}`);\n})\n\n\nflow.set('notificationTag', `${env.get('title')}_${randomId()}`);","finalize":"","x":298,"y":80,"wires":[["368c9723.5876f8"]]},{"id":"974bd48d.c253e8","type":"switch","z":"6dc0247c.d7210c","name":"which action?","property":"eventData.event.action","propertyType":"msg","rules":[{"t":"eq","v":"action1Id","vt":"flow"},{"t":"eq","v":"action2Id","vt":"flow"},{"t":"eq","v":"action3Id","vt":"flow"}],"checkall":"true","repair":false,"outputs":3,"x":1024,"y":176,"wires":[[],[],[]]},{"id":"204dbcfc.144ae4","type":"status","z":"6dc0247c.d7210c","name":"","scope":["f9e57204.71076","5bc7345c.07b1cc","a622c92a.2d9898","368c9723.5876f8"],"x":124,"y":272,"wires":[[]]},{"id":"5bc7345c.07b1cc","type":"function","z":"6dc0247c.d7210c","name":"build message","func":"const latestMessage = flow.get('latestMessage');\nconst event = msg.payload.event;\n\nlatestMessage.eventData = msg.payload;\nlatestMessage.payload = latestMessage._originalPayload;\ndelete latestMessage._originalPayload;\n\nif(env.get('userInfo')) {\n const userData = msg.userData.find(u => u.id === msg.payload.context.user_id);\n latestMessage.userData = userData;\n}\n\nif(msg.event_type === 'mobile_app_notification_cleared') {\n node.status({\n text: `cleared at: ${getPrettyDate()}`,\n shape: 'dot',\n fill: 'blue'\n });\n \n return [null, latestMessage];\n}\n\nconst index = [1,2,3].find(i => event[`action_${i}_key`] === event.action);\nnode.status({\n text: `${event[`action_${index}_title`]} at: ${getPrettyDate()}`,\n shape: 'dot',\n fill: 'green'\n});\n\nreturn latestMessage;\n\n\nfunction getPrettyDate() {\n return new Date().toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour12: false,\n hour: 'numeric',\n minute: 'numeric',\n });\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":832,"y":176,"wires":[["974bd48d.c253e8"],[]]},{"id":"8d3bdc0c.37493","type":"switch","z":"6dc0247c.d7210c","name":"belongs here?","property":"payload.event.tag","propertyType":"msg","rules":[{"t":"eq","v":"notificationTag","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":432,"y":176,"wires":[["83ad2004.d04d"]]},{"id":"271e4479.b9249c","type":"ha-api","z":"6dc0247c.d7210c","name":"get user info","debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\"type\": \"config/auth/list\"}","dataType":"json","location":"userData","locationType":"msg","responseType":"json","x":822,"y":128,"wires":[["5bc7345c.07b1cc"]]},{"id":"3618f055.6909a","type":"server-events","z":"6dc0247c.d7210c","name":"mobile_app_notification_cleared","event_type":"mobile_app_notification_cleared","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":false,"x":194,"y":224,"wires":[["8d3bdc0c.37493"]]},{"id":"83ad2004.d04d","type":"switch","z":"6dc0247c.d7210c","name":"fetch user info?","property":"userInfo","propertyType":"env","rules":[{"t":"true"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":624,"y":176,"wires":[["271e4479.b9249c"],["5bc7345c.07b1cc"]]},{"id":"9d85d137.fe487","type":"switch","z":"6dc0247c.d7210c","name":"","property":"clear_notification","propertyType":"msg","rules":[{"t":"null"},{"t":"nnull"}],"checkall":"true","repair":false,"outputs":2,"x":143,"y":80,"wires":[["f9e57204.71076"],["a622c92a.2d9898"]],"l":false},{"id":"a622c92a.2d9898","type":"function","z":"6dc0247c.d7210c","name":"create clear notification","func":"const services = env.get('service');\nif(!services) {\n node.status({\n text: 'no services defined',\n shape: 'ring',\n fill: 'red'\n });\n return; \n}\n\nservices.trim().split(/,\\s*/).forEach(service => {\n if(!service) return;\n \n msg.payload = {\n service,\n data: {\n message: \"clear_notification\",\n data: {\n tag: flow.get('notificationTag'),\n }\n }\n };\n node.send(msg);\n});\n\nnode.done();","outputs":1,"noerr":0,"initialize":"","finalize":"","x":318,"y":128,"wires":[["368c9723.5876f8"]]},{"id":"9bfe567c.3d10c8","type":"server-events","z":"6dc0247c.d7210c","name":"mobile_app_notification_action","event_type":"mobile_app_notification_action","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":false,"x":194,"y":176,"wires":[["8d3bdc0c.37493"]]},{"id":"368c9723.5876f8","type":"api-call-service","z":"6dc0247c.d7210c","name":"","version":1,"debugenabled":false,"service_domain":"notify","service":"","entityId":"","data":"","dataType":"json","mergecontext":"callServiceData","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":550,"y":80,"wires":[[]]},{"id":"581acb2a.792564","type":"subflow:6dc0247c.d7210c","z":"31cdc.c18e83244","name":"","env":[{"name":"service","value":"mobile_app_jason","type":"str"},{"name":"title","value":"testing actionable notification","type":"str"},{"name":"action1Title","value":"action one","type":"str"},{"name":"action2Title","value":"open HA","type":"str"},{"name":"action2Uri","value":"/lovelace/0","type":"str"},{"name":"action3Title","value":"action three","type":"str"},{"name":"userInfo","type":"bool","value":"true"},{"name":"group","value":"","type":"str"}],"x":436,"y":1136,"wires":[["d2b46240.6de89"],["a63fb7bc.64af88"],["2f4904b8.568d3c"],["75334c15.956694"]]},{"id":"aa8e9e73.4957f","type":"inject","z":"31cdc.c18e83244","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"abc","payload":"default payload","payloadType":"str","x":202,"y":1136,"wires":[["581acb2a.792564"]]},{"id":"d2b46240.6de89","type":"debug","z":"31cdc.c18e83244","name":"action1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":652,"y":1088,"wires":[]},{"id":"a63fb7bc.64af88","type":"debug","z":"31cdc.c18e83244","name":"action2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":652,"y":1120,"wires":[]},{"id":"2f4904b8.568d3c","type":"debug","z":"31cdc.c18e83244","name":"action3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":652,"y":1152,"wires":[]},{"id":"75334c15.956694","type":"debug","z":"31cdc.c18e83244","name":"cleared","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":652,"y":1184,"wires":[]},{"id":"81797230.4299e","type":"inject","z":"31cdc.c18e83244","name":"clear_notification","props":[{"p":"clear_notification","v":"true","vt":"bool"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":208,"y":1184,"wires":[["581acb2a.792564"]]}]

0 comments on commit 51ad8f2

Please sign in to comment.