Question for anyone using any of the Alexa nodes.
Is there a way to create a notification like amazon does when a package has been delivered or weather alert?
I tried 'Push Notification' but it didn't seem to do anything.
Question for anyone using any of the Alexa nodes.
Is there a way to create a notification like amazon does when a package has been delivered or weather alert?
I tried 'Push Notification' but it didn't seem to do anything.
I've used the "Alexa Routine" node and "Announcement" setting.
That's really no different than the regular speak function with the exception of the notification sound at the beginning.
What I'm looking for is the type of notifications that are queued until you say 'Alexa read my notifications'
Like when you get a package delivery and the echo is pulsing yellow (iirc).
Gotcha - have that disabled so don't use that functionality. I might give it try though for giggles. It does seem like the "Push Notification" thing should work though. What kind of formatting are you using? nvmd - see it's straight up text.
Can confirm - Unable to get a push notification either.
edit: I think Push Notification has something to do with pushing alerts to your phone but not sure..
edit2: I wonder if there is a way to set a reminder instead. You can give commands to Alexa via that node.
also this:
Confirmed Push goes to Alexa on phone.
I thought of reminder but its essentially an alarm.
Notify Me skill looks like it might be the solution. Looking into it now,
Thanks
Can confirm the Notify Me skill works and there is a NR node for it.
Sure! It's very very simple though.. but is a good example of a subflow 
[{"id":"d18a2b0.2e233d8","type":"subflow","name":"Simple Toggle on/off","info":"","category":"","in":[{"x":80,"y":120,"wires":[{"id":"b8812dc3.a5b85"}]}],"out":[{"x":740,"y":80,"wires":[{"id":"fa67c9c1.a69a88","port":0}]},{"x":740,"y":160,"wires":[{"id":"6e76f259.b1f72c","port":0}]}],"env":[],"color":"#DDAA99","status":{"x":740,"y":300,"wires":[{"id":"1b03c1050aa50c9c","port":0}]}},{"id":"b8812dc3.a5b85","type":"switch","z":"d18a2b0.2e233d8","name":"Is on/off","property":"payload.value","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":240,"y":120,"wires":[["fa67c9c1.a69a88"],["6e76f259.b1f72c"]]},{"id":"fa67c9c1.a69a88","type":"change","z":"d18a2b0.2e233d8","name":"on set off","rules":[{"t":"set","p":"command","pt":"msg","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":80,"wires":[["1b03c1050aa50c9c"]]},{"id":"6e76f259.b1f72c","type":"change","z":"d18a2b0.2e233d8","name":"off set on","rules":[{"t":"set","p":"command","pt":"msg","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":160,"wires":[["1b03c1050aa50c9c"]]},{"id":"1f6b7b17.d4a9b5","type":"comment","z":"d18a2b0.2e233d8","name":"set command based on on/off toggle ","info":"","x":260,"y":220,"wires":[]},{"id":"1b03c1050aa50c9c","type":"change","z":"d18a2b0.2e233d8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"command","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":300,"wires":[[]]},{"id":"3626ebc0facb3554","type":"subflow:d18a2b0.2e233d8","z":"af91369d.586338","name":"","x":550,"y":1320,"wires":[[],[]]}]
I have a much more sophisticated one called "advanced toggle".. but it might be overkill for stuff like this.
I've seen subflows but haven't got to the stage in my NR rabbit hole. Are they equivalent to a sub-routine in a conventional programming language?
What's the difference between this and the advanced?
Yes that's it exactly! Subflows are very good for standardizing your sequences. Easier to maintain and edit across all your stuff. EDIT: Maybe "function" is a better analogy.
Advanced accepts json input so you can use it for on/off, open/close and convert like "on/off" to "open/close" whatever. Also you can choose to invert "on/off" goes to "off/on" or just passthrough. It's very flexible but the parameters might be a little confusing.
[{"id":"049dd7eab1551ac1","type":"subflow","name":"AdvancedToggle","info":"","category":"","in":[{"x":60,"y":60,"wires":[{"id":"c11d7711d06a4d51"}]}],"out":[{"x":640,"y":80,"wires":[{"id":"c11d7711d06a4d51","port":0}]}],"env":[{"name":"INPUT","type":"json","value":"{\"payload.value\":\"on/off\"}"},{"name":"OUTPUT","type":"json","value":"[{\"command\":\"on\",\"arguments\":\"\"},{\"command\":\"off\",\"arguments\":\"\"}]"},{"name":"INVERT","type":"bool","value":"false"}],"meta":{},"color":"#FDF0C2","icon":"node-red-contrib-sun-position/inputTypeRandomNumber.svg","status":{"x":640,"y":200,"wires":[{"id":"c11d7711d06a4d51","port":0}]}},{"id":"c11d7711d06a4d51","type":"function","z":"049dd7eab1551ac1","name":"Based on Input and \"invert\" convert to Output","func":"\nvar input = env.get(\"INPUT\");\nvar output = env.get(\"OUTPUT\");\nvar invert = env.get(\"INVERT\");\n\n/* uncomment if want to pass parms in via msg \nif (msg.hasOwnProperty(\"at\") ) {\n if (msg.at.hasOwnProperty(\"input\") ) {\n input = msg.at.hasOwnProperty(\"input\");\n }\n if (msg.at.hasOwnProperty(\"output\") ) {\n output = msg.at.hasOwnProperty(\"output\");\n }\n if (msg.at.hasOwnProperty(\"invert\") ) {\n invert = msg.at.hasOwnProperty(\"invert\");\n }\n}\n*/\n\nvar retMsg;\nvar inputProp = Object.keys(input)[0];\nvar inputTypes = input[inputProp].split(\"/\");\nvar inputVal = getVal(msg,inputProp);\nvar valIndex = inputTypes.findIndex(type => type === inputVal.toString());\nvar val;\nif (valIndex != -1) {\n //retMsg = msg;\n var newIndex = (invert ? (valIndex == 0 ? 1 : 0) : valIndex );\n var oOutput = output[newIndex];\n \n if (oOutput.hasOwnProperty(\"_actions\")){\n \n outputActions = oOutput[\"_actions\"];\n //node.warn(outputActions)\n\n for (var i=0;i<outputActions.length;i++) {\n retMsg = {};\n oAction = outputActions[i];\n keys = Object.keys(oAction);\n for (var j=0;j<keys.length;j++) {\n val = oAction[keys[j]];\n setVal(retMsg,keys[j],val);\n }\n //node.warn(retMsg);\n node.send(retMsg);\n }\n \n } else {\n retMsg = {};\n keys = Object.keys(oOutput);\n for (var k=0;k<keys.length;k++) {\n val = oOutput[keys[k]];\n setVal(retMsg,keys[k],val);\n }\n node.send(retMsg);\n }\n node.done();\n\n}\n\n//return retMsg;\nreturn;\n\nfunction getVal(obj,propName) {\n\n var retVal;\n var props = propName.split(\".\");\n var name = props[0];\n \n if (props.length > 1) {\n if (obj.hasOwnProperty(name)) {\n props.shift();\n var newProps = props.join(\".\");\n retVal = getVal(obj[name],newProps)\n }\n } else {\n retVal = obj[name];\n }\n \n return retVal;\n\n}\n\n\nfunction setVal(obj,propName,val) {\n var props = propName.split(\".\");\n var name = props[0];\n\n if (props.length > 1) {\n if (!obj.hasOwnProperty(name)) {\n obj[name] = {};\n }\n \n props.shift();\n var newProps = props.join(\".\");\n setVal(obj[name],newProps,val)\n } else {\n obj[name] = val;\n }\n \n return;\n\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":140,"wires":[[]]},{"id":"ce9f98597e16b102","type":"subflow:049dd7eab1551ac1","z":"e6807da71ee5477b","name":"","x":1010,"y":740,"wires":[[]]}]
I used "subroutine" as I didn't want to confuse it with the actual "function" node.
I'm confused by this part of the subflow. Is it simply for monitoring the status of the subflow or does it send the on/off command to the HE device command node?

It's simply for monitoring status.. it appears underneath the subflow node. Very handy for troubleshooting and reading state without having to edit the subflow itself.
So for advanced toggle can I just feed it open/close events like from a door sensor or do I have to change the input payload.value to open/close and output command to same?
For simple toggle, why do you have two outputs in the sub-flow ? Why not a single output; after all both the commands go to the same command node?
I don't for the advanced toggle? Maybe you are seeing the status output? This was something I threw together so everyone's mileage may vary!
You should be able to do that - just define what you want in the input json and the output. PM me if you want!
Anyone seeing issues with their alexa routines (applestrudel) within the last hour ~9pm EST?
Alexa appears to be down
That's what I thought but just wanted to make sure it was not something I did.
Split an array of values into individual arrays
I was looking for an easier way to split an array (without having to loop through the arrays and split them in a function node) and discovered the $spread JSONATA function. Worked brilliantly but for some reason, it would not work for a date field returned from a SQL query on a mySQL database. The folks over on the Node-RED community suggested some other solutions, so thought I would share them here in case it helps someone.
[{"id":"337250983f7905d8","type":"inject","z":"9dd3cdef.2f2f38","name":"","props":[{"p":"payload"},{"p":"props","v":"[\"totalHomeuse\",\"gridToHome\",\"solarToHome\",\"batteryToHome\",\"totalSolar\",\"solarToGrid\",\"solarToBattery\",\"day\"]","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":267.6666564941406,"y":147.99989318847656,"wires":[["da751414a159fccd"]]},{"id":"da751414a159fccd","type":"function","z":"9dd3cdef.2f2f38","name":"generate dummy data (ignore me)","func":"\nconst templateRow = {\n totalHomeuse: 67.74,\n gridToHome: 34.62,\n solarToHome: 21.11,\n batteryToHome: 12.01,\n totalSolar: 34.88,\n solarToGrid: 0.05,\n solarToBattery: 13.72,\n day: \"2022-01-17T06:00:00.0002\"\n}\n\nconst data = []\nfor (let index = 0; index < 10; index++) {\n const element = RED.util.cloneMessage(templateRow);\n element.totalHomeuse = randomFloat(60,70)\n element.gridToHome = randomFloat(30,40)\n element.solarToHome = randomFloat(20,30)\n element.batteryToHome = randomFloat(10,20)\n element.totalSolar = randomFloat(30,40)\n element.solarToGrid = randomFloat(0.01,0.99)\n element.solarToBattery = randomFloat(11,14)\n element.day = new Date(Date.now() + ((index+1)*1000*60)).toISOString()\n data.push(element)\n}\nmsg.payload = data;\n\n\nreturn msg;\n\n\n/**\n* @param {number} min\n* @param {number} max\n*/\nfunction randomFloat(min, max) {\n return Math.random() * (max - min) + min;\n};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":505.6666564941406,"y":147.99989318847656,"wires":[["942662580d53e493","e3e67cb9207e5e23","2f1ca195.87b276","ff10a763.0f6b3","a39977a.9ef3d08"]]},{"id":"942662580d53e493","type":"debug","z":"9dd3cdef.2f2f38","name":"Dummy data","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":546.6666564941406,"y":57.99989318847656,"wires":[]},{"id":"e3e67cb9207e5e23","type":"function","z":"9dd3cdef.2f2f38","name":"toArrays - function","func":"\n//Props can be dynamically sent in via the msg object if required (to make it generic)\n/*const props = [\n \"totalHomeuse\",\n \"gridToHome\",\n \"solarToHome\",\n \"batteryToHome\",\n \"totalSolar\",\n \"solarToGrid\",\n \"solarToBattery\",\n \"day\"\n];\n*/\nconst props = msg.props\n\nmsg.result = toArrays(msg.payload, props)\nreturn msg;\n\n\n\n\n\n/**\n * Convert object properties in `data` to array of values\n * @param {any[]} data - Data to scan\n * @param {string[]} propNames - property names to collect\n*/\nfunction toArrays(data, propNames) {\n const result = {};\n propNames.forEach(p => {\n result[p] = [];\n data.forEach(e => {\n result[p].push(e[p]);\n })\n })\n return result;\n}\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":825.6665954589844,"y":221.99987030029297,"wires":[["66081cdb3d263701"]]},{"id":"2f1ca195.87b276","type":"change","z":"9dd3cdef.2f2f38","name":"Split selected values - JSONATA spread","rules":[{"t":"set","p":"totalHomeuse","pt":"msg","to":"$spread(payload.totalHomeuse)","tot":"jsonata"},{"t":"set","p":"dateTime","pt":"msg","to":"$spread(payload.day)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":895.3333435058594,"y":72.99999237060547,"wires":[["e8504ec0.fc0998"]]},{"id":"ff10a763.0f6b3","type":"change","z":"9dd3cdef.2f2f38","name":"Split selected values - JSONATA keys","rules":[{"t":"set","p":"totalHomeuse","pt":"msg","to":"$spread(payload.totalHomeuse)","tot":"jsonata"},{"t":"set","p":"dateTime","pt":"msg","to":"$$payload.day","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":892.6665954589844,"y":147.66663360595703,"wires":[["9e3e4f84.4bbc2"]]},{"id":"a39977a.9ef3d08","type":"change","z":"9dd3cdef.2f2f38","name":"Split all - JSONATA keys","rules":[{"t":"set","p":"payload","pt":"msg","to":"$keys($$.payload).${$:$lookup($$.payload,$)}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":845.6665954589844,"y":298.6666488647461,"wires":[["4ac93c40.a17184"]]},{"id":"66081cdb3d263701","type":"debug","z":"9dd3cdef.2f2f38","name":"Split all - function","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"result","targetType":"msg","statusVal":"payload","statusType":"auto","x":1033.6666564941406,"y":219.99987030029297,"wires":[]},{"id":"e8504ec0.fc0998","type":"debug","z":"9dd3cdef.2f2f38","name":"After selected - spread","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1198.3333435058594,"y":72.99999237060547,"wires":[]},{"id":"9e3e4f84.4bbc2","type":"debug","z":"9dd3cdef.2f2f38","name":"After selected - keys","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1192.6665954589844,"y":147.66661834716797,"wires":[]},{"id":"4ac93c40.a17184","type":"debug","z":"9dd3cdef.2f2f38","name":"Split all - keys","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1079.6665954589844,"y":298.6666488647461,"wires":[]}]
I don't fully understand the Javascript in the function node nor do I understand the JSONATA used to navigate the structure in the split all solution. The other two are much easier to grasp!