Pure fun with Alexa and Alexa Skills

@haegar - More than happy to clear this up. The blueprints were just the beginning. The real backbone of my setup with the node-red-contrib-ecolect node I'm using. Then, of course, I've had to get creative with my flows to make it all work. It's still a work in progress and since I'm new to node-red I'm sure it could be much more efficient. Overall, the results are much better than I expected.

Attached are some example flows of what I'm doing. The file is pretty big so I'm not 100% sure it's saved in the correct format. If it doesn't work, let me know. It's probably way more information than you want, but it should give you a pretty good idea of my setup. This won't necessarily work right out of the box as there are some specific things you'll need to set up (such as your Alexa account) but I've tried to put in notes for everything that you might wonder about, but if you have any questions, please feel free to ask. Also, if you have any suggestions for how to improve it, I'm all ears.

alexa flow examples.txt (95.7 KB)

1 Like

Just a slight aside ...

To avoid having to create skills or do other stuff, there are two easy methods of asking Alexa for customised commands that you can then intercept and parse yourself in Node-RED

  1. Say "Alexa, Simon says please do this complicated query that otherwise would be rejected"

My name is Simon so I don't have a problem with this :slight_smile:

or

  1. Say "Alexa, please do this complicated query that otherwise would be rejected stop"

Only problem with that is my wife would never go for that. :wink: She barely tolerates the home automation stuff as it is… especially after the infamous automatic sprinkler incident. :grimacing:

Oh I do hope you are going to share the story :smile:

Here ya go....

3 Likes

Hi Rich,
Thanks for sharing your flow.

I tried importing your flow. OK there were loads of missing nodes ( I can deal with that).
It seemed to prevent my Deploy button from working as it kept it in the red state.
I deleted your flow and re-booted my Pi and my original flows are working again (phew).
It will be interesting to hear if anyone else encounters any issues importing your text file.

PS: Loved reading your funny story - brilliant.

Not sure if it matters but the code was too big to just paste into a post and so I put the data into a plain text file. I was able to import it by going into the text file and selecting everything and pasting it into node-red, rather than importing the file directly. If there’s a better way to share it I’d be happy to reformat it.

Oh and it’s formatted for node-red 3.0. Could it have something to do with that perhaps?

I used NR v2.1.3 although I don't it should matter.
However I'll try importing it to one of my RPi-4B servers running NR v3

So on this topic, I'm trying to use one function node (instead of five) to output to Alexa the state of each of my open doors. For some reason Alexa gets the data over and over again regarding the Sliding Glass Door in particular.

I'm sure the problem is the syntax of the IF statements, but I'm not sure how to fix it. Ultimately, I'd like Alexa to go through the list and just announce each door that's open and if none are, then just say they're all closed. It does do that, it just does it over and over and over...

Can someone who understands this stuff take a look at this and tell me where I'm going wrong?

var device_name = msg.payload.alexa.name;
var summary = msg.payload.alexa.description.summary;
var doorOpenCount = msg.payload.doorsOpenCount;
var stateFrontDoor = msg.payload.doors.state[0];
var stateSlidingGlassDoor = msg.payload.doors.state[1];
var stateLaundryRoomDoor = msg.payload.doors.state[2];
var stateGarageDoor = msg.payload.doors.state[3];
var stateGarageManDoor = msg.payload.doors.state[4];

if ((summary != "alexa") && (summary != "")) 
{
    if (stateFrontDoor == "Front Door open") 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status": { text: "the front door is open" }
            }    
        }
    }
    node.send(msg);    

    if (stateSlidingGlassDoor == "Sliding Glass Door open") 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status":{ text: "the sliding glass door is open"}
            }   
        }
    }
    node.send(msg); 
 
    if (stateLaundryRoomDoor == "Laundry Room Door open") 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status":    { text: "the laundry room door is open"}
            }
        }
    }
    node.send(msg);

    if (stateGarageDoor == "Garage Door open") 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status":    { text: "the garage door is open"}
            }
        }
    }
    node.send(msg);
    
    if (stateGarageManDoor == "Garage Man Door open") 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status":    { text: "the garage man door is open"}
            }
        }
    }
    node.send(msg);
    
    if (doorOpenCount == 0) 
    {
        msg.payload = {};

        msg =
        {
            topic: "Alexa_response",
            device_name: device_name,
            payload:
            {
                "status":    { text: "all doors are closed"}
            }
        }
    }
    node.send(msg);

} 
    else 
    {
        return null;
    }

Hi Rich,
Taken a very quick look at your code. I think each node.send(msg); should be within each if block.
Could you try moving them as per this screen-shot and see if that improves things.
alex_rich
I've only shown one example, you obviously need to adjust all six lines.

Well, that kind of worked. Now she's repeating "the front door is open" and "the sliding glass door is open" over and over and over. Hahahaha!

I know I can make it work by breaking it into separate function nodes and then using a switches to filer them before hand, but I have a bunch of windows to sort out and I'm hoping to avoid that many nodes.

What are you using to trigger what looks like the code in a function node?
Is she telling the truth? Are those doors in fact 'open'?

I'm using a voice command to request a status report based on the node-red-contrib-ecolect nodes I've been using. I'm setting the msg.payloads from global variables that are set in a different flow whenever a door is opened or closed. The function node is reporting the proper open doors, but for some reason (in this particular example) it's spitting out the front door message four times and the sliding glass door message eight times. I've kind of solved this on the Alexa side of it by changing each door to a different topic, throwing in an RBE node, and using a trigger node to limit messages.

Here is the whole flow as I have it at the moment. It's also in Node-RED 3.0 so if it doesn't import properly it's probably because of the junction nodes. They don't play nice in pre 3.0 versions.

Thanks for taking a look at this Dave. You're a rockstar!

[
    {
        "id": "e55c2f05901c8c12",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "e785dc4d93d37913",
        "type": "group",
        "z": "e55c2f05901c8c12",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "f03f2b62d705a9a9",
            "12629c5b51b91b6f",
            "0e2fa87c82b5d3e7",
            "9c0917c47d0bd31a",
            "add335380f9b9e10",
            "9364587735a769a1",
            "b60d88c3e19baffb",
            "04ce09d6740cb8b0",
            "0593ce028092d24b",
            "7b1fc2bb5d5d0dd7",
            "6036c24f40391777",
            "d532d63f5fb3bd8e",
            "6b7739521a9d2acf",
            "6e9b657c06eb6639",
            "81cfadcb18d5c07a",
            "5fb55bf45e0fcd60",
            "d6869ace46d8914e",
            "d818b848df698f0b",
            "0d37c9c2a427964d",
            "0f98d0b05e45d770"
        ],
        "x": 294,
        "y": 154,
        "w": 1652,
        "h": 307
    },
    {
        "id": "d6869ace46d8914e",
        "type": "junction",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "x": 1060,
        "y": 180,
        "wires": [
            [
                "9c0917c47d0bd31a"
            ]
        ]
    },
    {
        "id": "d818b848df698f0b",
        "type": "junction",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "x": 660,
        "y": 280,
        "wires": [
            [
                "9364587735a769a1",
                "0593ce028092d24b"
            ]
        ]
    },
    {
        "id": "0d37c9c2a427964d",
        "type": "junction",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "x": 320,
        "y": 180,
        "wires": [
            [
                "f03f2b62d705a9a9",
                "b60d88c3e19baffb"
            ]
        ]
    },
    {
        "id": "f03f2b62d705a9a9",
        "type": "change",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "set payload from summary",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.description.summary",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 440,
        "y": 400,
        "wires": [
            [
                "12629c5b51b91b6f"
            ]
        ]
    },
    {
        "id": "12629c5b51b91b6f",
        "type": "ecolect",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "Voice Commands for Status Reports",
        "topics": [
            {
                "name": "Status",
                "phrases": "status report [on] [the] {item}\ngive me a status report on {item}\n{item} status report\nreport on {item}\nstatus report which {item} are open",
                "values": [
                    {
                        "name": "item",
                        "type": "enumeration",
                        "enumerations": [
                            "doors",
                            "open doors",
                            "windows",
                            "open windows",
                            "fans",
                            "celing fans",
                            "exhaust fans",
                            "Alexa volume",
                            "Temperature",
                            "Notifications",
                            "Cat Presence",
                            "HVAC",
                            "Batteries",
                            "Tampers",
                            "Weather",
                            "Alarm",
                            "Who's home / Who's away",
                            "Pending Notifications",
                            "Alexa Connection Issues",
                            "Vacuum Stats",
                            "Televisions On/Off",
                            "Rachio",
                            "Outside Motion Events during the night or since last check",
                            "Node-RED uptime",
                            "Awake/Home time",
                            "Sleep Report",
                            "Cat Litter box",
                            "Cat Food ?",
                            "Node-RED backups",
                            "Node-RED updates",
                            "Hubitat updates",
                            "device firmware updates"
                        ]
                    }
                ]
            }
        ],
        "outputs": 2,
        "x": 510,
        "y": 340,
        "wires": [
            [
                "0593ce028092d24b"
            ],
            [
                "9364587735a769a1"
            ]
        ]
    },
    {
        "id": "0e2fa87c82b5d3e7",
        "type": "switch",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "Status Reports",
        "property": "values.item",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "doors",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "windows",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "fans",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 980,
        "y": 280,
        "wires": [
            [
                "d6869ace46d8914e",
                "6e9b657c06eb6639"
            ],
            [
                "d6869ace46d8914e"
            ],
            []
        ]
    },
    {
        "id": "9c0917c47d0bd31a",
        "type": "debug",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "debug 883",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 970,
        "y": 220,
        "wires": []
    },
    {
        "id": "add335380f9b9e10",
        "type": "alexa-remote-routine",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "Alexa device",
        "account": "",
        "routineNode": {
            "type": "speak",
            "payload": {
                "type": "regular",
                "text": {
                    "type": "str",
                    "value": "Sorry, can you repeat that? Sounds like you said some bull shit about reports."
                },
                "devices": {
                    "type": "msg",
                    "value": "payload.alexa.deviceSerialNumber"
                }
            }
        },
        "x": 950,
        "y": 400,
        "wires": [
            []
        ]
    },
    {
        "id": "9364587735a769a1",
        "type": "join",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "mode": "custom",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": true,
        "timeout": "",
        "count": "1",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "num",
        "reduceFixup": "",
        "x": 770,
        "y": 400,
        "wires": [
            [
                "add335380f9b9e10"
            ]
        ]
    },
    {
        "id": "b60d88c3e19baffb",
        "type": "change",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "alexa",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 420,
        "y": 280,
        "wires": [
            [
                "d818b848df698f0b"
            ]
        ]
    },
    {
        "id": "04ce09d6740cb8b0",
        "type": "alexa-remote-routine",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "Alexa device",
        "account": "",
        "routineNode": {
            "type": "speak",
            "payload": {
                "type": "regular",
                "text": {
                    "type": "msg",
                    "value": "payload"
                },
                "devices": {
                    "type": "msg",
                    "value": "device_name"
                }
            }
        },
        "x": 1850,
        "y": 360,
        "wires": [
            []
        ]
    },
    {
        "id": "0593ce028092d24b",
        "type": "join",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "mode": "custom",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": true,
        "timeout": "",
        "count": "1",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "num",
        "reduceFixup": "",
        "x": 770,
        "y": 280,
        "wires": [
            [
                "0e2fa87c82b5d3e7"
            ]
        ]
    },
    {
        "id": "7b1fc2bb5d5d0dd7",
        "type": "change",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "set payload",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.status.text",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1370,
        "y": 380,
        "wires": [
            [
                "81cfadcb18d5c07a",
                "5fb55bf45e0fcd60"
            ]
        ]
    },
    {
        "id": "6036c24f40391777",
        "type": "function",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "Open Doors",
        "func": "var device_name = msg.payload.alexa.name;\nvar summary = msg.payload.alexa.description.summary;\nvar doorOpenCount = msg.payload.doorsOpenCount;\nvar stateFrontDoor = msg.payload.doors.state[0];\nvar stateSlidingGlassDoor = msg.payload.doors.state[1];\nvar stateLaundryRoomDoor = msg.payload.doors.state[2];\nvar stateGarageDoor = msg.payload.doors.state[3];\nvar stateGarageManDoor = msg.payload.doors.state[4];\n\nif ((summary != \"alexa\") && (summary != \"\")) \n{\n    if (stateFrontDoor == \"Front Door open\") \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"Front_Door\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\": { text: \"the front door is open\" }\n            } \n        }\n        node.send(msg);   \n    }\n        \n\n    if (stateSlidingGlassDoor == \"Sliding Glass Door open\") \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"Sliding_Glass_Door\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\":{ text: \"the sliding glass door is open\"}\n            }   \n        }\n        node.send(msg); \n    }\n\n    if (stateLaundryRoomDoor == \"Laundry Room Door open\") \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"Laundry_Room_Door\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\":    { text: \"the laundry room door is open\"}\n            }\n        }\n        node.send(msg);\n    }    \n\n    if (stateGarageDoor == \"Garage Door open\") \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"Garage_Door\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\":    { text: \"the garage door is open\"}\n            }\n        }\n        node.send(msg);\n    }\n    \n    if (stateGarageManDoor == \"Garage Man Door open\") \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"Garage_Man_Door\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\":    { text: \"the garage man door is open\"}\n            }\n        }\n        node.send(msg);\n    }\n\n    if (doorOpenCount == 0) \n    {\n        msg.payload = {};\n\n        msg =\n        {\n            topic: \"All_Doors\",\n            device_name: device_name,\n            payload:\n            {\n                \"status\":    { text: \"all doors are closed\"}\n            }\n        }\n    node.send(msg);\n    }\n    return msg;\n} \n    else \n    {\n        return null;\n    }",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1210,
        "y": 320,
        "wires": [
            [
                "7b1fc2bb5d5d0dd7",
                "d532d63f5fb3bd8e"
            ]
        ]
    },
    {
        "id": "d532d63f5fb3bd8e",
        "type": "debug",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "debug 889",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1190,
        "y": 420,
        "wires": []
    },
    {
        "id": "6b7739521a9d2acf",
        "type": "debug",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "debug 890",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1450,
        "y": 200,
        "wires": []
    },
    {
        "id": "6e9b657c06eb6639",
        "type": "change",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload.doors",
                "pt": "msg",
                "to": "statusReport.doors",
                "tot": "global"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1240,
        "y": 260,
        "wires": [
            [
                "6036c24f40391777",
                "6b7739521a9d2acf"
            ]
        ]
    },
    {
        "id": "81cfadcb18d5c07a",
        "type": "debug",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "debug 892",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1530,
        "y": 420,
        "wires": []
    },
    {
        "id": "5fb55bf45e0fcd60",
        "type": "rbe",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "func": "rbe",
        "gap": "",
        "start": "",
        "inout": "out",
        "septopics": true,
        "property": "payload",
        "topi": "topic",
        "x": 1495,
        "y": 380,
        "wires": [
            [
                "0f98d0b05e45d770"
            ]
        ],
        "l": false
    },
    {
        "id": "0f98d0b05e45d770",
        "type": "delay",
        "z": "e55c2f05901c8c12",
        "g": "e785dc4d93d37913",
        "name": "",
        "pauseType": "queue",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "5",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 1650,
        "y": 360,
        "wires": [
            [
                "04ce09d6740cb8b0"
            ]
        ]
    },
    {
        "id": "1aec2cf425ce7ed5",
        "type": "alexa-remote-event",
        "z": "e55c2f05901c8c12",
        "name": "",
        "account": "",
        "event": "ws-device-activity",
        "x": 150,
        "y": 120,
        "wires": [
            [
                "919a2038f190ad08"
            ]
        ]
    },
    {
        "id": "919a2038f190ad08",
        "type": "switch",
        "z": "e55c2f05901c8c12",
        "name": "",
        "property": "payload.conversionDetails.CUSTOMER_TRANSCRIPT[0].transcriptText",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "alexa",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 190,
        "y": 180,
        "wires": [
            [
                "0d37c9c2a427964d"
            ],
            []
        ]
    }
]

OK - I've managed to import your code, I'll take a detailed look later.

1 Like

Thanks @DiverRich for your flow example. Unfortunately its too big with too many non-installed nodes to be imported in my setup (You know you can export a sub selection of nodes from a flow window?)

But what I am trying to point out is the problem with Alexa, not NodeRed!

I try to phrase it even more simple:
if you define a blueprint phrase "switch on the light" in your Alexa account
what is your Alexa answer to a sentence like "switch on the light in the bathroom"?

In may case Alexa will answer "I do not understand you".

Thus all the super sophisticated post-processing in NR does not help because thats not the Alexa answer I want.

Oh - I wish I was as I'd have loads of money to buy a shed-load of electronic-kit (ha, ha, ha).

I think I've tamed Alexa using a blueprint. My real problem is that I don't quite understand how to use multiple IFs in a function node and I think it's looping somehow. I've got other flows that are set up basically the same that work well. The difference with those are that I've broken each IF into its own function node and used switch nodes to filter them. I figured there must be a way to reduce all those function nodes into one, since they all basically do the same thing. I just can't seem to figure out how to format the function node properly.

Of course I could just use more function nodes like my other flows, but my motivation for trying to combine them is that I have lots of window contact sensors I'm keeping track of and I didn't really want to have that many function nodes for them if I can just use one.

I considered using a state machine until I realized my windows alone would have 512 different states to take into account. :joy:

ok, so how do you get your trigger phrases defined for NR?

node-red-contrib-ecolect

It’s magical once you get it set up. Takes a bit of experimenting, but you can do some pretty cool stuff with voice commands with it.

I've found this excellent video by Csongor Varga that gives a brilliant introduction to the Ecolect node.

I'm going to investigate it further later as I think it has "legs-on-it".

1 Like