Introduction
Hey all, this is my first post, so go easy on me I just got started with Hass.io a couple weeks ago and I’ve been addicted ever since. I’ve been working to move the entirety of my home automation into Node-Red and implement some those features we’ve been waiting for the longest, including our desire for room-aware commands. Last night, I succeeded in developing a new, very straightforward approach for making room aware commands with Node-Red. Since I didn’t see this approach documented anywhere, I thought I’d share it here so that others may benefit from it.
TL;DR;
This approach gives you the ability to dynamically issue voice commands to a device based on your own room-aware logic, which you may also combine with other predicates at your discretion. The approach is meant avoid the need to create a custom Alexa Skill or write any custom code, though you may do so if you wish to go the extra mile and improve the implementation.
Prerequisites:
- Node-Red installed via the Hass.io add-on (technically, you can do this with vanilla node-red and not just the Hass.io add-on, but I haven’t tested it in a standalone instance yet)
- Have 586837r’s node-red-contrib-alexa-remote2 package for Node-Red installed https://flows.nodered.org/node/node-red-contrib-alexa-remote2
- (Optional) Have datech’s node-red-contrib-amazon-echo package for Node-Red installed https://flows.nodered.org/node/node-red-contrib-amazon-echo
As noted above, the third package is optional and is required if you want to incorporate device emulation into your flows, as I have. For example, if you are using my solution to issue commands like “turn on the fan” to the fan in the room you’re in then you may want to emulate a device called “Fan”. Note that because I used this package for nodes in my flow, you may have difficulty importing my flow without it. Also, it’s in my manual install instructions, but you can skip the parts that use it if you want to.
My flows:
[{"id":"35964044.fcf53","type":"tab","label":"Contextual Routines","disabled":false,"info":""},{"id":"35bdb0e0.53f29","type":"alexa-remote-event","z":"35964044.fcf53","name":"","account":"d99d5f0e.4d0f5","event":"ws-device-activity","x":110,"y":500,"wires":[["a26a3b25.554268"]]},{"id":"1a5b5511.75c5db","type":"amazon-echo-device","z":"35964044.fcf53","name":"Fan","topic":"","x":330,"y":200,"wires":[[]]},{"id":"545ebb02.da3e74","type":"switch","z":"35964044.fcf53","name":"Route: Contextual Routine","property":"payload.description.summary","propertyType":"msg","rules":[{"t":"regex","v":"turn on (the )?fan","vt":"str","case":false},{"t":"regex","v":"turn (the )?fan on","vt":"str","case":false},{"t":"regex","v":"turn off (the )?fan","vt":"str","case":false},{"t":"regex","v":"turn (the )?fan off","vt":"str","case":false},{"t":"regex","v":"(set|turn) (the )?fan ((on|to) )?low","vt":"str","case":false},{"t":"regex","v":"(set|turn) (the )?fan ((on|to) )?medium","vt":"str","case":false},{"t":"regex","v":"(set|turn) (the )?fan ((on|to) )?high","vt":"str","case":false}],"checkall":"true","repair":false,"outputs":7,"x":600,"y":500,"wires":[["a3767ece.d2e99"],["a3767ece.d2e99"],["b94005ac.8f4828"],["b94005ac.8f4828"],["9a8de045.916b6"],["f6f03dd2.05328"],["951d9ca0.ccb17"]],"outputLabels":["Turn on","Turn on","Turn off","Turn off","Set low","Set medium","Set high"]},{"id":"b94005ac.8f4828","type":"switch","z":"35964044.fcf53","name":"Route: Fan off","property":"payload.deviceSerialNumber","propertyType":"msg","rules":[{"t":"eq","v":"[MASTER BEDROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[GUEST ROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[KID'S ROOM ECHO'S SERIAL NUMBER]","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":920,"y":260,"wires":[["cc815395.81107"],["a71773aa.a7cfa"],["b2c077b2.fa0458"]],"outputLabels":["Master Bedroom","Guest Room","Office"]},{"id":"9a8de045.916b6","type":"switch","z":"35964044.fcf53","name":"Route: Fan low","property":"payload.deviceSerialNumber","propertyType":"msg","rules":[{"t":"eq","v":"[MASTER BEDROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[GUEST ROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[KID'S ROOM ECHO'S SERIAL NUMBER]","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":920,"y":420,"wires":[["1f3f79ac.0d4826"],["1fc26ad0.fdf265"],["bbc0c776.bfe818"]],"outputLabels":["Master Bedroom","Guest Room","Office"]},{"id":"f6f03dd2.05328","type":"switch","z":"35964044.fcf53","name":"Route: Fan medium","property":"payload.deviceSerialNumber","propertyType":"msg","rules":[{"t":"eq","v":"[MASTER BEDROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[GUEST ROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[KID'S ROOM ECHO'S SERIAL NUMBER]","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":930,"y":580,"wires":[["65787ee0.02993"],["1a8e26ed.8395f9"],["5c630a47.ce7804"]],"outputLabels":["Master Bedroom","Guest Room","Office"]},{"id":"951d9ca0.ccb17","type":"switch","z":"35964044.fcf53","name":"Route: Fan high","property":"payload.deviceSerialNumber","propertyType":"msg","rules":[{"t":"eq","v":"[MASTER BEDROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[GUEST ROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[KID'S ROOM ECHO'S SERIAL NUMBER]","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":920,"y":740,"wires":[["3ce2a8d3.776708"],["8a8c5698.828958"],["9a3c1659.0b29e8"]],"outputLabels":["Master Bedroom","Guest Room","Office"]},{"id":"a3767ece.d2e99","type":"switch","z":"35964044.fcf53","name":"Route: Fan on","property":"payload.deviceSerialNumber","propertyType":"msg","rules":[{"t":"eq","v":"[MASTER BEDROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[GUEST ROOM ECHO'S SERIAL NUMBER]","vt":"str"},{"t":"eq","v":"[KID'S ROOM ECHO'S SERIAL NUMBER]","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":920,"y":100,"wires":[["8ba6d633.30fa68"],["b7f0f5d0.1d4938"],["15374f8.3db2bb1"]],"outputLabels":["Master Bedroom","Guest Room","Office"]},{"id":"8ba6d633.30fa68","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"48aa8e73-2067-48f7-9625-3ec34ea69363","action":"turnOn"}]},"outputs":1,"x":1120,"y":60,"wires":[[]]},{"id":"b7f0f5d0.1d4938","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"b0b1ec9e-7723-4826-ba85-f569b465dd6d","action":"turnOn"}]},"outputs":1,"x":1120,"y":100,"wires":[[]]},{"id":"15374f8.3db2bb1","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"a8174fea-b7b1-4331-bf17-5da01a963729","action":"turnOn"}]},"outputs":1,"x":1120,"y":140,"wires":[[]]},{"id":"cc815395.81107","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn off","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"48aa8e73-2067-48f7-9625-3ec34ea69363","action":"turnOff"}]},"outputs":1,"x":1120,"y":220,"wires":[[]]},{"id":"a71773aa.a7cfa","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn off","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"b0b1ec9e-7723-4826-ba85-f569b465dd6d","action":"turnOff"}]},"outputs":1,"x":1120,"y":260,"wires":[[]]},{"id":"b2c077b2.fa0458","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn off","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"a8174fea-b7b1-4331-bf17-5da01a963729","action":"turnOff"}]},"outputs":1,"x":1120,"y":300,"wires":[[]]},{"id":"1f3f79ac.0d4826","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on low","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"48aa8e73-2067-48f7-9625-3ec34ea69363","action":"setPercentage","value":{"type":"num","value":"33"}}]},"outputs":1,"x":1130,"y":380,"wires":[[]]},{"id":"1fc26ad0.fdf265","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on low","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"b0b1ec9e-7723-4826-ba85-f569b465dd6d","action":"setPercentage","value":{"type":"num","value":"33"}}]},"outputs":1,"x":1130,"y":420,"wires":[[]]},{"id":"bbc0c776.bfe818","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on low","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"a8174fea-b7b1-4331-bf17-5da01a963729","action":"setPercentage","value":{"type":"num","value":"33"}}]},"outputs":1,"x":1130,"y":460,"wires":[[]]},{"id":"65787ee0.02993","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on medium","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"48aa8e73-2067-48f7-9625-3ec34ea69363","action":"setPercentage","value":{"type":"num","value":"66"}}]},"outputs":1,"x":1140,"y":540,"wires":[[]]},{"id":"1a8e26ed.8395f9","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on medium","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"b0b1ec9e-7723-4826-ba85-f569b465dd6d","action":"setPercentage","value":{"type":"num","value":"66"}}]},"outputs":1,"x":1140,"y":580,"wires":[[]]},{"id":"5c630a47.ce7804","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on medium","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"a8174fea-b7b1-4331-bf17-5da01a963729","action":"setPercentage","value":{"type":"num","value":"66"}}]},"outputs":1,"x":1140,"y":620,"wires":[[]]},{"id":"3ce2a8d3.776708","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on high","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"48aa8e73-2067-48f7-9625-3ec34ea69363","action":"setPercentage","value":{"type":"num","value":"100"}}]},"outputs":1,"x":1130,"y":700,"wires":[[]]},{"id":"8a8c5698.828958","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on high","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"b0b1ec9e-7723-4826-ba85-f569b465dd6d","action":"setPercentage","value":{"type":"num","value":"100"}}]},"outputs":1,"x":1130,"y":740,"wires":[[]]},{"id":"9a3c1659.0b29e8","type":"alexa-remote-smarthome","z":"35964044.fcf53","name":"Turn on high","account":"d99d5f0e.4d0f5","config":{"option":"action","value":[{"entity":"a8174fea-b7b1-4331-bf17-5da01a963729","action":"setPercentage","value":{"type":"num","value":"100"}}]},"outputs":1,"x":1130,"y":780,"wires":[[]]},{"id":"a26a3b25.554268","type":"change","z":"35964044.fcf53","name":"Strip Wake Word","rules":[{"t":"change","p":"payload.description.summary","pt":"msg","from":"^(alexa )?","fromt":"re","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":500,"wires":[["545ebb02.da3e74"]]},{"id":"62a42905.95f0b8","type":"amazon-echo-hub","z":"35964044.fcf53","port":"80","processinput":0,"x":130,"y":200,"wires":[["1a5b5511.75c5db"]]},{"id":"d99d5f0e.4d0f5","type":"alexa-remote-account","z":"","name":"Zachary's Account","authMethod":"proxy","proxyOwnIp":"192.168.1.227","proxyPort":"3456","cookieFile":"/config/node-red/add-ons/node-red-contrib-alexa-remote2/alexa.json","refreshInterval":"3","alexaServiceHost":"pitangui.amazon.com","amazonPage":"amazon.com","acceptLanguage":"en-US","userAgent":"","useWsMqtt":"on","autoInit":"on"}]
My Solution: Room-Aware Routines
After thoroughly researching, reviewing and experimenting with the known solutions in the market (see Comparison with Alternative Solutions, below), I was admittedly dissatisfied with the available solutions to this problem and decided to come up with my own that combines as many of the benefits from each of the two most prominent solutions and as few of the caveats as possible. I wanted to make something easily extensible that remains close to both Alexa and Node-Red (and the plugins I use), as reliable and predictable as possible (no race conditions), and as low-effort to set up and manage as possible. As an added benefit, my approach features the ability to use regex matching for routine commands, and I plan to further enhance it by incorporating TTS.
How it Works
The solution works by defining a virtual (emulated hue) device to represent the device that you want to be able to control using room-aware commands, and then attaching a listener to your Alexa account that listens to all activity and routes any known room-aware commands appropriately. Following along with the image below:
- When any command is issued to an echo device, the “on device activity” handler is run and kicks off the flow
- A “change” node is used to strip the wake word from the command, if present (i.e. if the user didn’t pause for Alexa to respond before uttering the command); the wake-word is stripped ahead of time rather than simply being matched in the regex-based router for reusability (specifically, for sharing with you all, as some of you may use a custom wake word) and also to shorten the required pattern string (none of the solutions are great for performance and they really don’t need our help becoming worse when it’s easily avoidable )
- A “switch” node is used to inspect the command (not the room yet - we want to stop processing ASAP whenever possible) string and match it against the known routine text. I use regex for this, as I’m willing to trade some performance for simplicity, readability and robustness (e.g. I make words like “the” optional, match synonyms like “set” and “turn”, etc.). Feel free to instead use strings (like normal routines) if you’re so inclined.
- If the command is recognized (matched) as a known room-aware routine then it’s sent to another “switch” node that determines the room-specific action that should be called for the command. Note that using the mentioned Node-Red packages also gives you the ability to have Alexa state custom responses when no device was matched (e.g. “there’s no fan in this room to turn on” if I said “turn on the fan” while in the living room). I won’t go into this in this post, but with a little tinkering you should be able to figure it out.
Setup Instructions
You can either import my flow and use it as a starting point, or you can set it up manually, following the steps, below:
- Make sure that you have all required prerequisites installed
- Add a new “Alexa Event” node to your flow. By default, it should be set to trigger “On Device Activity”. Be sure to set the account to a working account, if you have not done so already (side-note: if you want your routines to keep working you have to have the File Path set in the account so that the plugin can store your oauth tokens without you having to constantly log in)
- Add a “change” node and wire the output of your “Alexa Event” node to your “change” node’s input.
- Set your change node to strip out your wake-word from the beginning of the
msg.payload.description.summary
property - Add a “switch” node and wire the output of your “change” node to your “switch” node’s input. This switch is your “room-aware routine router” (I call them contextual routines in my flow because I have a predefined naming convention that I didn’t want to conflict with or change)
- Using regex matching, string comparison or your preferred matching predicate, create at least one switch case that checks for your desired room-aware routine (e.g. “turn the fan on”). Remember to leave the wake-word out, since it’s been stripped, and to write in all lowercase. If using regex, since Alexa will always pass the command in lowercase, it is recommended to not ignore case (performance). Note: for the purpose of these instructions, it is assumed that your routine aligns with a typical command that would be used to control a device, e.g. “turn the fan on”. This is necessary for the optional steps below, but you can make the routine whatever you want and skip those steps if you so desire.
- Add another “switch” node to your flow, connecting the output corresponding to the new routine-aware case that you defined in the previous step to the input of the new switch. This new “switch” is going to be your room-router and will decide which room-specific action to perform.
- Using string comparison, add a case for each room that you want to be able to issue the command in, comparing the
msg.payload.deviceSerialNumber
to the serial number of the echo device in that room. You can find the serial number of your echo devices in the Alexa App, by going to the device and clicking “About”. - (Somewhat Optional) Add your desired “Alexa Smarthome”, “Alexa Routine”, or other desired logic nodes for each room and wire them appropriately to run when the case for their corresponding room is true (wire their inputs to the switch’s output corresponding to the case associated with their room). Following our example, add a new “Alexa Smarthome” node to the flow and wire it’s input to the switch output corresponding to the case you created in the previous step. Set your new Alexa Smarthome node to use your account and set it to “Turn On” the fan device in the matching room. Note: if you have already created your emulated “Fan” device then do not wire this action to that device, but rather wire it to the actual device that you wish to control.
- (Optional) Assuming that you wish to be able to run a routine that sounds like a normal device command (e.g. “turn on the fan”) you will want to create an emulated device named “fan” so that Alexa doesn’t say “I couldn’t find a device named ‘fan’” every time you issue a room-aware fan command. If you haven’t already, add a “amazon echo hub” node to your flow (if you have one in another flow you shouldn’t need to add another one, unless you want isolated hub services - off topic, but I can’t think of a good reason to do this). Then add a “amazon echo device” node and give it the exact name that you wish to use for your device. When you’re done, have Alexa discover devices and she’ll find the virtual one you created. That’s it. You don’t need to actually do anything else with your device, since it’s just there to enable you to make commands without Alexa throwing a fit.
Eliminating the “[device] doesn’t do that” messages for commands hue devices don’t support
You can actually eliminate these messages pretty easily by creating routines in your Alexa App that don’t actually do anything. The routines won’t prevent your room-aware routines from being called. However, it may be more work than you’d like to create all of the routines in the Alexa App to match your room-aware routines. For example, I use a the following regex to match the command to set a fan to medium speed:
(set|turn) (the )?fan ((on|to) )?medium
There are two possible states for the verb, (set|turn)
, two possible states for the presence of the article, (the )?
, and three possible states for the preposition, ((on|to) )?
. Thus there are 2*2*3=12
valid variants of my room-aware routine for setting the fan to medium speed. That’s 12 different dummy routines that I’d have to make (insert Alexa Skill here ). In fairness, Alexa often lets you skip articles/prepositions when speaking commands and I’ve experienced her doing the same for and matching routines for me before. However, it’s not reliable so you may want to add these anyway, or just do what I do (though not in my exported flow, above) and have Alexa say something funny, like “Just kidding, I set the fan to medium for you” after she tells you that “fan doesn’t support that” (if you go that route, I suggest using SSML interjections for the joke; my wife was in tears laughing when she heard it the first time ).
Overall Pros:
- No external scripts, accounts, systems or tools beyond Node-Red, the aforementioned plugins and Alexa
- Can combine your room aware logic with other predicates to create complex room-aware routines and device commands
- No custom code beyond nodes, and no function nodes used
- Creates routines that can be executed based on a regex match against the spoken command (e.g.
^(alexa )?turn on (the )?fan
) - Extensible and maintainable through Node-Red
Overall Cons:
- Version I posted provides a routine-like approach that requires you to match the utterance and execute the action without being able to leverage Alexa’s native utterance processing features (i.e. no AVS) and could be improved to leverage Alexa Voice Service (AVS) and TTS in the future
- Although this post describes several techniques to eliminate or avoid some of these issues, it’s worth mentioning that some commands may result in “[device name] does not support that” messages from Alexa for certain actions when using device emulation (e.g. “set the fan to medium”, since emulated devices are hue devices) or a “no device found named [device name]” if using commands for a device that hasn’t yet been emulated
Comparison with and Review of Alternative Solutions
Most of the solutions that I’ve seen for room-aware voice commands involve one of two things:
- Clever TTS scripts that look at the last echo device used (often paired with hass.io service/entity configuration)
- Assigning a separate account to each echo device
Below, I describe each approach based on my experiments with and research into various approaches matching each.
Alternative 1: TTS scripts using lastecho/lastalexa
Okay, this one doesn’t necessarily use Node-Red, but you can make it use Node-Red and it’s one of the most popular solutions I found, so I’m including it . At a high-level, this approach involves using a CLI (Command-Line Interface) script to call the Alexa cloud service and retrieve an identifier for the last echo device (“lastalexa” is typically the name, but from what I’ve seen this is a misnomer and I believe it should be “lastecho” - feel free to correct me on this if you can explain the reasoning behind it) to which a command was issued. The idea is that the last used echo would be the one the user just spoke the room-aware command to. The retrieved ID can then be used in conditional logic to determine what room to perform the action in and the original command can be updated from “turn the fan on” to “turn the fan on in the guest room”, leveraging the room determined by the output of the CLI calls. Please note that I’ve seen several different approaches to this one, and some are more streamlined than the multi-step process described, but the overall approach and pattern remains the same and I believe this explanation is easier to follow for readers picking this up.
Perhaps the biggest benefit of the “last echo” approach is that its use of CLI-based Alexa service calls makes it superior for the processing of utterances/spoken text and mapping it to the desired commands than my own approach. This is because the CLI scripts used in the “last echo” approach have support for leveraging Alexa’s own TTS/text processing capabilities, enabling developers to pass Alexa the text form of the spoken command and let her decide what to do with it. In contrast, my approach is more akin to routines in that the spoken text must be matched in custom logic/Node-Red rules in order to determine which action should run. This is an area of opportunity for my approach, in that I could use my existing logic for determining the echo device to which the command was issued, modify the utterance text in Node to reflect the actual name of the device to command and then use TTS and AVS to send the resulting utterance to Alexa for processing.
As a software architect, I’m not at all a fan of the “last echo” approach. It’s hacky and ripe for conflicts and unexpected behavior when two devices are used at relatively the same time. My wife and I both work from home and often issue commands at similar times. Commands issued within 10 seconds of each other can easily cause unexpected results due to the delay between the spoken command and when it is actually processed. This delay is impacted by everything from network latency to the user’s proximity to other devices when the command was spoken and beyond. As an example, yesterday when I was experimenting with the “lastecho” approach, I issued a test room-aware command with a fan just a couple of seconds before my wife coincidentally issued a command in a different room with a fan. Her fan turned on instead of mine. She’s frequently cold and was…displeased…with the experience . It should suffice to say that this option wasn’t for me, but I’ll also add a few more objective rationales against the “last echo” approach from a technical perspective:
- All of the scripts that I’ve seen for this are reverse-engineered versions of Alexa web apps or other tools that can change at any time. In a way, my solution is no better, since the Node-Red plugins that I use are also both based on reverse-engineered and/or unofficial Alexa APIs. Choose your poison.
- Race-condition roulette is something that should be avoided whenever possible. This is when you have two things that could possibly happen out of order (like my wife and I both issuing commands in separate rooms and the possibility that the last echo might thus result in the wrong room being returned to me). With that said, home automation is still in its infancy and we, as hobbyists, tend to be willing to deal with a little slippage from time to time. If this is something you’re okay with then there are pretty simple and reasonably well-documented hass.io and platform-agnostic approaches to this on the web.
Alternative 2: Assigning a separate account per echo device
This is perhaps the most popular approach that I’ve seen out there for room-aware commands, likely because it’s perhaps the most straightforward approach, requires minimal effort and shares the benefit of Alexa being responsible for utterance/spoken language processing with the “last echo” approach. The multi-account approach leverages the “Amazon Household” feature of Alexa that allows users to associate multiple accounts (intended for family members) with the household and its Alexa-enabled devices. Following this approach, instead of assigning a separate account to each family member, a separate account is assigned to each echo device (or at least to each of the ones that you want to run room-aware commands on). The multi-account approach requires datech’s node-red-contrib-amazon-echo package for Node-Red, and I recommend also using 586837r’s node-red-contrib-alexa-remote2 package for Node-Red to perform the resulting actions on Alexa-connected devices. Additionally, for this approach, the echo devices that you plan to issue room-aware commands to must all be on separate accounts and have their own static IPs (internal to the network is fine; technically, you can combine some clever logic nodes from 586837r’s node-red-contrib-alexa-remote2 nodes in order to dynamically get assigned IP addresses for devices to match room-aware commands against, but I won’t be going into that today). Following this approach, room-specific devices are modeled in Node-Red as a virtual (emulated hue) device node. As such, to make room-specific fans that you control through room-aware commands like “turn on the fan”, you would create a “Fan” emulated hue device node to be shared by all of the room-specific fans (this will become clearer as you read on). When a command comes into one of the emulated hue device nodes, a switch (conditional) node downstream of the emulated device node is used to inspect the IP address of the device that issued the command (found in the msg.meta.insert.details.ip
property) and determine what action to take based on the room the echo device with the inspected IP is associated with.
If you’re unfamiliar with this solution, then you may be wondering why you have to use separate accounts for each echo to make that work, since it sounds like a good solution on its own. After some research and experimentation, it is clear (though I wasn’t able to find official documentation to substantiate) that within the account and/or network Alexa chooses a “master” device from which to issue commands to connected devices, and so all commands for a given account will appear to have come from the same IP address. We work around this by associating each device with a different account, thus making each its own “master”. Following with our fan example from before, when the room-aware “turn on the fan” command comes into the emulated hue “Fan” node, the command object will be holding the IP of the echo device that the command was spoken to, so long as that device is on its own account (i.e. the device is guaranteed to be the “master”). For example, if I was standing in the guest room when I said “Alexa, turn on the fan”, then the command object will hold the IP address of the Guest Room Echo. The command object is then passed from the “Fan” node to a switch node, in order to decide what to do with it. In our example, the switch node will match the IP address against the known IP address (or dynamically retrieved using …remote2 nodes) of the Guest Room Echo, and then will then turn the fan on in that room. If you are using 586837r’s node-red-contrib-alexa-remote2 package for Node-Red then downstream of the switch’s output for commands with IPs matching the Guest Room Echo condition you would have an “Alexa Smarthome” node configured to turn on “Guest Room Fan”.
This isn’t a bad approach, and it benefits greatly from sticking very close to native Alexa functionality. However, there are several limitations that should be mentioned:
- It doesn’t scale well. You only get 2 adult and 4 child accounts per household, so assuming you have 1 account as the “main” account you only have 5 more that you can use for your devices. In my case, my wife likes to actually use a different account so she can easily switch to her own music, calendar, etc. and to ensure that we don’t see gifts purchased for us by one another when looking at order history. Even if that wasn’t the case, I still have more rooms that I would want this to work in than it can support, so it doesn’t really scale.
- As with my approach, it’s limited by the capabilities of the Node-Red plugins used to implement it, including emulated hue capabilities, and so some commands (e.g. “Set the fan to medium”) will work but will also result in Alexa saying “Fan cannot do that”. The workarounds I described for this issue with my approach will also work for this one.
- Like all of the known approaches I’ve found (including my own), this approach is dependent upon tools written against unofficial/reverse-engineered Alexa API’s that could change at any time
Regarding the scalability issue, one thought that occurred to me that I have not yet tried is to achieve the same result as this approach through the use of subnets or isolated networks. This seemed like a “mouse meets elephant gun” scenario, requiring additional hardware (routers and possibly switches) for something that really shouldn’t, interfering with multi-room music (less important for bedrooms, but still a valid point), and requiring additional effort to configure bandwidth limiting in order to avoid the additional networks eating up your available network bandwidth. In theory, I expect that this would work but It wasn’t something I was willing to pursue. If anyone else has experimented with this already and is willing to save me a few hours and can share their observations then I would be most appreciative.