Setting Phone alarms from Calandar Events in Node Red

Initial Premmis and issues

So, this is a personal project I have wanted to set aside time to work on for quite a while
The idea was simple enough to set multiple alarms so I would wake up on time, depending on whether I was in the office or working from home.

Seeing a post on setting phone alarms via the HA companion app was the catalyst I needed to work this out and be somewhat redundant if my home assistant instance locked up overnight, as it can do on my set up.

One large stumbling block was using Node Red as my go to automation method, I wanted to keep everything there for simplicity but the call service node for Listing calander events will error out with ‘"“Call-service error. Service call requires responses but caller did not ask for responses”’, using the API node directly with home assisstant solved this error giving me an array I could pharse in node red.

The Solution

It’s not the most elegant solution; however, it sets the alarms on my phone the night before, letting me check these before I sleep and gives me peace of mind that it is done. It also sets the Alarm Text entity for use with other automation.

If you want to attempt this, I recommend looking at the Android Developer Documentation for what you can set in these. types of notifications that manipulate your phone.

I also have a shared calendar with my partner, so starting my work events with “Name- Work” allows them to be filtered for only my work schedule.

The code

[{"id":"a545e9f00454d609","type":"inject","z":"9ec0978b12323a24","name":"","props":[{"p":"now","v":"","vt":"date"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"30 18 * * *","once":false,"onceDelay":0.1,"topic":"","x":190,"y":540,"wires":[["c5848b22cfe662ab"]]},{"id":"ed15f837b157b578","type":"ha-api","z":"9ec0978b12323a24","name":"","server":"c2394423.98abb8","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\t   \"type\": \"execute_script\",\t   \"sequence\": [\t       {\t           \"service\": \"calendar.list_events\",\t           \"data\": {\t               \"duration\":{\t                    \"hours\": 36,\t                    \"minutes\": 0,\t                    \"seconds\": 0}           \t           },\t           \"target\": {\t               \"entity_id\": [\t                   \"calendar.family\"     // Set your Cal Name here            \t               ]             \t           },\t           \"response_variable\": \"service_result\"         \t       },\t       {\t           \"stop\": \"done\",\t           \"response_variable\": \"service_result\"         \t       }     \t   ] \t}","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":450,"y":540,"wires":[["e35f310cb01ca0c7"]]},{"id":"e35f310cb01ca0c7","type":"function","z":"9ec0978b12323a24","name":"Filter for only Work events","func":"// Check if the payload is an array and filter the events\nif (Array.isArray(msg.payload.response.events)) {\n    msg.payload= msg.payload.response.events.filter(event => event.summary.startsWith(\"Start Word\")); // Set what your Cal event starts with this is how I filter my events\n} else {\n    msg.payload = [\"Broken\"]; // If payload is not an array or empty, set it to an empty array\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":540,"wires":[["4ae6d704ef2211ca"]]},{"id":"4ae6d704ef2211ca","type":"switch","z":"9ec0978b12323a24","name":"","property":"payload[0].summary","propertyType":"msg","rules":[{"t":"cont","v":"Office","vt":"str"},{"t":"cont","v":"Home","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":870,"y":540,"wires":[["5e698f334ba216c2"],["14d3d75e75867fe4"],[]]},{"id":"5e698f334ba216c2","type":"moment","z":"9ec0978b12323a24","name":"Office Day","topic":"","input":"payload[0].start","inputType":"msg","inTz":"Europe/London","adjAmount":"1.5","adjType":"hours","adjDir":"subtract","format":"DD/MM/YY HH:mm","locale":"C","output":"alarm1","outputType":"msg","outTz":"Europe/London","x":1050,"y":500,"wires":[["8c2c15dd760ae145"]]},{"id":"14d3d75e75867fe4","type":"moment","z":"9ec0978b12323a24","name":"WFH Day","topic":"","input":"payload[0].start","inputType":"msg","inTz":"Europe/London","adjAmount":"1","adjType":"hours","adjDir":"subtract","format":"DD/MM/YY HH:mm","locale":"C","output":"alarm1","outputType":"msg","outTz":"Europe/London","x":1040,"y":560,"wires":[["de09025dc4ce25bd"]]},{"id":"de09025dc4ce25bd","type":"api-call-service","z":"9ec0978b12323a24","name":"Alarm Text","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"input_text","service":"set_value","areaId":[],"deviceId":[],"entityId":[],"data":"{\"value\":msg.alarm1}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1370,"y":520,"wires":[["9e1c080bfafa0ad1"]]},{"id":"cf744a4f265cd487","type":"function","z":"9ec0978b12323a24","name":"Hour Min Split Alarm 1","func":"msg.hour = msg.alarm1.slice(-5,-3)\nmsg.min = msg.alarm1.slice(-2)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1220,"y":760,"wires":[["88830e243336cbab"]]},{"id":"4e19e3f90beffc06","type":"moment","z":"9ec0978b12323a24","name":"Alarm 3","topic":"","input":"alarm2","inputType":"msg","inTz":"Europe/London","adjAmount":"10","adjType":"minutes","adjDir":"add","format":"DD/MM/YY HH:mm","locale":"C","output":"alarm3","outputType":"msg","outTz":"Europe/London","x":1320,"y":640,"wires":[["aef7d7be0f93c92e"]]},{"id":"7c2462330b9220e2","type":"moment","z":"9ec0978b12323a24","name":"Alarm 2","topic":"","input":"alarm1","inputType":"msg","inTz":"Europe/London","adjAmount":"15","adjType":"minutes","adjDir":"add","format":"DD/MM/YY HH:mm","locale":"C","output":"alarm2","outputType":"msg","outTz":"Europe/London","x":1320,"y":600,"wires":[["4e19e3f90beffc06"]]},{"id":"aef7d7be0f93c92e","type":"moment","z":"9ec0978b12323a24","name":"Alarm 4","topic":"","input":"alarm3","inputType":"msg","inTz":"Europe/London","adjAmount":"5","adjType":"minutes","adjDir":"add","format":"DD/MM/YY HH:mm","locale":"C","output":"alarm4","outputType":"msg","outTz":"Europe/London","x":1320,"y":680,"wires":[["5c337d2ad5af9787"]]},{"id":"8c2c15dd760ae145","type":"moment","z":"9ec0978b12323a24","name":"Alarm Office","topic":"","input":"alarm1","inputType":"msg","inTz":"Europe/London","adjAmount":"45","adjType":"minutes","adjDir":"add","format":"DD/MM/YY HH:mm","locale":"C","output":"alarmOffice","outputType":"msg","outTz":"Europe/London","x":1210,"y":500,"wires":[["de09025dc4ce25bd"]]},{"id":"6baacba641c07690","type":"switch","z":"9ec0978b12323a24","name":"","property":"date","propertyType":"msg","rules":[{"t":"eq","v":"tomorrow","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1710,"y":520,"wires":[["7c2462330b9220e2"]]},{"id":"c5848b22cfe662ab","type":"moment","z":"9ec0978b12323a24","name":"Tomorrow","topic":"","input":"now","inputType":"msg","inTz":"Europe/London","adjAmount":"1","adjType":"days","adjDir":"add","format":"DD/MM/YY","locale":"C","output":"tomorrow","outputType":"msg","outTz":"Europe/London","x":320,"y":540,"wires":[["ed15f837b157b578"]]},{"id":"9e1c080bfafa0ad1","type":"function","z":"9ec0978b12323a24","name":"Date","func":"msg.date = msg.alarm1.slice(0, 8)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1550,"y":500,"wires":[["6baacba641c07690"]]},{"id":"5c337d2ad5af9787","type":"switch","z":"9ec0978b12323a24","name":"Office Day?","property":"alarmOffice","propertyType":"msg","rules":[{"t":"nempty"},{"t":"empty"}],"checkall":"true","repair":false,"outputs":2,"x":850,"y":780,"wires":[["cf744a4f265cd487","caf79251db28d223","2a5bd235569d0582","5cd3220a1a5a3ffb","58e0143254fb517a"],["cf744a4f265cd487","caf79251db28d223","2a5bd235569d0582","5cd3220a1a5a3ffb"]]},{"id":"caf79251db28d223","type":"function","z":"9ec0978b12323a24","name":"Hour Min Split Alarm 2","func":"msg.hour = msg.alarm2.slice(-5,-3)\nmsg.min = msg.alarm2.slice(-2)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1220,"y":820,"wires":[["d9d97be443cb76e8"]]},{"id":"2a5bd235569d0582","type":"function","z":"9ec0978b12323a24","name":"Hour Min Split Alarm 3","func":"msg.hour = msg.alarm3.slice(-5,-3)\nmsg.min = msg.alarm3.slice(-2)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1220,"y":880,"wires":[["ea6d5cf5d68126f2"]]},{"id":"5cd3220a1a5a3ffb","type":"function","z":"9ec0978b12323a24","name":"Hour Min Split Alarm 4","func":"msg.hour = msg.alarm4.slice(-5,-3)\nmsg.min = msg.alarm4.slice(-2)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1220,"y":940,"wires":[["edd92b5d6c1f89dd"]]},{"id":"58e0143254fb517a","type":"function","z":"9ec0978b12323a24","name":"Alarm Office","func":"msg.alarmOffice = \"24/09/23 10:45\"\nmsg.hour = msg.alarmOffice.slice(-5,-3)\nmsg.min = msg.alarmOffice.slice(-2)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1190,"y":1000,"wires":[["cdb1f15b0cd3495a"]]},{"id":"d9d97be443cb76e8","type":"delay","z":"9ec0978b12323a24","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1365,"y":820,"wires":[["bfe13bc446f6636a"]],"l":false},{"id":"ea6d5cf5d68126f2","type":"delay","z":"9ec0978b12323a24","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1365,"y":880,"wires":[["0b94223c20fc4d50"]],"l":false},{"id":"edd92b5d6c1f89dd","type":"delay","z":"9ec0978b12323a24","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1365,"y":940,"wires":[["533c783d4bbf2c2f"]],"l":false},{"id":"513d87d649f84e96","type":"inject","z":"9ec0978b12323a24","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":560,"y":780,"wires":[["5c337d2ad5af9787"]]},{"id":"cdb1f15b0cd3495a","type":"delay","z":"9ec0978b12323a24","name":"","pauseType":"delay","timeout":"20","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1365,"y":1000,"wires":[["2bec2df12f3fbc2c"]],"l":false},{"id":"bfe13bc446f6636a","type":"api-call-service","z":"9ec0978b12323a24","name":"Phone Alarm 2","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"notify","service":"notify","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"command_activity\",\t   \"data\": {\t       \"intent_action\": \"android.intent.action.SET_ALARM\",\t       \"intent_extras\":             \"android.intent.extra.alarm.HOUR:\"&\t       msg.hour&\",android.intent.extra.alarm.MINUTES:\"&\t       msg.min&\",android.intent.extra.alarm.SKIP_UI:true\"                                       \t   }         \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":820,"wires":[[]]},{"id":"0b94223c20fc4d50","type":"api-call-service","z":"9ec0978b12323a24","name":"Phone Alarm 3","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"notify","service":"notify","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"command_activity\",\t   \"data\": {\t       \"intent_action\": \"android.intent.action.SET_ALARM\",\t       \"intent_extras\":             \"android.intent.extra.alarm.HOUR:\"&\t       msg.hour&\",android.intent.extra.alarm.MINUTES:\"&\t       msg.min&\",android.intent.extra.alarm.SKIP_UI:true\"                                       \t   }         \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":880,"wires":[[]]},{"id":"533c783d4bbf2c2f","type":"api-call-service","z":"9ec0978b12323a24","name":"Phone Alarm 4","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"notify","service":"notify","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"command_activity\",\t   \"data\": {\t       \"intent_action\": \"android.intent.action.SET_ALARM\",\t       \"intent_extras\":             \"android.intent.extra.alarm.HOUR:\"&\t       msg.hour&\",android.intent.extra.alarm.MINUTES:\"&\t       msg.min&\",android.intent.extra.alarm.SKIP_UI:true\"                                       \t   }         \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":940,"wires":[[]]},{"id":"2bec2df12f3fbc2c","type":"api-call-service","z":"9ec0978b12323a24","name":"Phone Alarm 5","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"notify","service":"notify","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"command_activity\",\t   \"data\": {\t       \"intent_action\": \"android.intent.action.SET_ALARM\",\t       \"intent_extras\":             \"android.intent.extra.alarm.HOUR:\"&msg.hour&\t       \",android.intent.extra.alarm.MINUTES:\"&msg.min&\t       \",android.intent.extra.alarm.SKIP_UI:true,android.intent.extra.alarm.MESSAGE:Need to Leave Now\"                                       \t   }         \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":1000,"wires":[[]]},{"id":"88830e243336cbab","type":"api-call-service","z":"9ec0978b12323a24","name":"Phone Alarm 1","server":"c2394423.98abb8","version":5,"debugenabled":false,"domain":"notify","service":"notify","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"message\": \"command_activity\",\t   \"data\": {\t       \"intent_action\": \"android.intent.action.SET_ALARM\",\t       \"intent_extras\":             \"android.intent.extra.alarm.HOUR:\"&\t       msg.hour&\",android.intent.extra.alarm.MINUTES:\"&\t       msg.min&\",android.intent.extra.alarm.SKIP_UI:true\"                                       \t   }         \t}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":760,"wires":[[]]},{"id":"c2394423.98abb8","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Something I had tried to do was reduce the number of Call Services for Phone Notifications however piping these in from a function node as I have done before doesn’t seem to work quite right or I’m missing something obvious.

All in all, it does what I wanted, and I thought I’d share this project as it pulls together a lot of information and could be helpful for others taking on similar projects. Or to show that the ability to call notifications on Android opens much more functionality than I realised on first inspection.