Mastering Node-RED: Custom Alexa Commands + Node-RED Dashboard

May 30, 2018

Mastering Node Red Part 2

Today on the hookup we’re going to learn how to use Node-RED to control anything in our smart home with Amazon echo, and set up custom user interfaces using the Node-RED dashboard.

This is part 2 of my Mastering Node RED series, if you’re just starting with node red I highly recommend you watch part 1 of this series first, click ***point*** that link to go there now.  We’re going to be using a bunch of custom nodes in this video that are not included in the standard node-RED package.  I’ve included all of the names of these packages in the description below.  To install them click on the hamburger icon in the upper right corner and select manage palette, then click on the install tab and input the names of the packages into the search field.

Lets start with amazon echo.  If you’re using home assistant you already have a few ways to incorporate amazon alexa commands into your home automation including emulated hue and home assistant cloud.  So why should we even bother looking at amazon echo in node red? 1. Simplicity:  Never before has it been so easy to set up a new alexa command 2. Customizability: having it in node red means that the payload of your commands is infinitely customizable. And 3: Locality: Using the alexa local node causes your raspberry pi to act as the hub for each of these devices and removes any reliance on cloud servers.  A major theme that you will see in my videos is that I really don’t like cloud services, and although alexa itself is a cloud service, not using a skill provided by a third party greatly decreases the security concerns in the alexa platform… other than amazon itself having all your data.

 

Because the  Alexa Local node is actually just another emulated hue device that means it not only responds to on/off commands, but also to brightness messages, This means you can say things like “turn on the kitchen light” but also “set the blinds to 50%” or “set that charger to 3”.  Lets walk through the setting up my outdoor shades.  I’m going to make an alexa local node and call it “Test Shades”, and I’m going to pipe it into a debug node, just so we can get an idea of what’s coming out of this message. I’ll hit deploy and and jump into the alexa app on my phone, after going to smart home “add device” my new test shade will be discovered quickly.  Lets test it out “alexa turn the test shade to 40%”, you’ll notice that my debug node didn’t really tell me much, we’re going to need to click on the debug node and select “output complete message object”.  Now lets try that again “alexa turn on the test shade”.  Now you can see I’ve got WAY more information in there.  Here’s what we see as part of this message object:

Msg.bri is 40 because I told it to set to 40%

Msg. on_off command: is false because I didn’t specifically tell it to turn on or off

Msg.payload: is on, because 40% is of course at least partially on

Change direction: 0 (if you have any idea what this means or how to make it equal 1, go ahead and post down in the comments)

Bri_normallized: .4 this is just the brightness out of 1

On: “true” because 40% is not 0%

Device name, light ID, and port aren’t super important for this automation because they won’t change based on the command I give to alexa.

When I programmed these shades I noted it takes almost exactly 13 full rotations of the bar to roll the shades up and down, so when I programmed the different stop points on the shade I just made them 0-13.  This is all well and good when you’re writing custom MQTT messages, but how do we translate this into a brightness percentage out of 100?  The answer is the range node.  If you’ve ever used the map function in Arduino this node works the same way.  We tell it the range of the message we’re receiving (in this case 0-100 in the msg.bri variable) and the range of the message we’d like to have, which for my shades happens to be 0-13.  The result of this flow will be to have the shade turn to a specific % based on the command that I give it… but there’s a problem… This system remembers the previous brightness when the on/off commands are issued, but if I say to turn the shade on, I actually want it to turn on to 100%.  To do this I’m going to use a switch node.  In this node I’m going to check the msg.on_off_command variable.  If it’s true, I want to set the shades to 13, if it’s off I want to set the value to zero.  I’m using function nodes here because I need to have correctly formatted json to send to the call services node.  Lets do a really quick crash course on writing JSON.

I’m gonna hop over to the services tab under developer tools to write my json. We’re trying to send the input number set value service, lets generate as much stuff as we can with the dropdown menus.  I stupidly have my couch shade called input_slider1, I should fix that, but it’s not going to happen right now.  Now you can see down below that we can send a value property in this json object as well, but how?  It’s super easy.  Each parameter is separated by a comma and each entry needs quotation marks, so to add the value parameter we’ll just add comma, quotes, value, end quote, colon, quote, some value, end quote.  Now lets copy it into our function node, and we’re going to have a couple of if statements.  If msg.payload == “on” meaning I issued the on command, then I want to set the value to 13, and if msg.payload == “off” I want to set the value to 13.  Easy enough.

Now we’re going to use this same json that we wrote to set the shades to custom heights.   To do this we’ll just paste in our json from before but we’re going to replace the “some value” part with our msg.bri value that we’ve reduced to a 0-13 range.  Notice that since msg.bri is a variable we don’t want to have it in quotation marks.

Now our flow checks to see if I specifically used the “turn on” or “turn off” command and sets to all the way down if I did, and to a specific percentage value if I didn’t.  This is just one example for what you can do with alexa and node red, but the sky’s the limit .

 

Speaking of things with limitless possibilities, lets talk about node-red dashboard.  I know what you’re gonna say: you already have a dashboard in home assistant with all kinds of cool options like floorplan and HA dashboard, why do you need another dashboard?  Let me convince you.  In this example we’re going to make a slick alarm panel ui, without writing any code at all.

Lets start with some dashboard basics.  The UI has different pages called tabs, and each tab has different modules called groups.  In the panel on the right where your debug tab usually lives you’ll notice that you have a new tab called “dashboard”.  In this tab you can customize different attributes of your UI like color and size.  This is also where we’re going to add new screens to our UI by clicking the add tab button.  For our example I’m going to add a tab called “alarm panel: and a group called “keypad”.  I’m going to make this group 6 units wide because I want to have a 3 button wide keypad and I want each button to be 2×2.

Now that I’ve got a group I just need to populate it.  To do that I’m going to add 12 buttons corresponding to 0-9, asterisk, and clear.  For each of these buttons except clear I’m going to have the payload be exactly the same as the label on the button, but it certainly doesn’t have to be.

Once I’ve got all the buttons set up and arranged in the order I’d like them to be I can preview my alarm panel by going to my normal node-red url and replacing everything after the base url with /ui.  You can move your buttons around as needed until you are happy with the way your ui looks.

Once you’ve got your ui looking nice, we need to program it.  We’re going to program it a simple way first, and then we’re going to get a little fancy.

Let’s start by making sure that our user is putting in the right code.  To do this we’re going to need to join our consecutive msg.payloads together in a join node.  I want a 4 digit pin, so I’m going to set up a few options in here pertaining to that.  I want to send the joined message after 4 parts, or 20 seconds, whichever happens first.  The 20 second part basically just makes the current code entry time out after 20 seconds.  The other part you’ll notice here is that there is a default option that says that if the node receives a payload of message.complete with a value of “true” it will automatically send the message on, even without 4 parts joining or 20 seconds passing.  This allows us to set up a “clear” button using a change node that allows the user to start over if they enter an incorrect pin.

We obviously only want the keypad to respond if the correct message is sent, so we’re going to send this message to a switch node that looks for the correct pin.  For our example I’m going to use one eight seven four which is my current number of subscribers at the time of writing this.  After this node, the easiest thing to do would be to toggle the alarm on or off using a call services node and the input_boolean.toggle service.  But that wouldn’t really be that useful because we probably need some time to leave the house after turning the alarm on.

So instead of that call service node we’re going to check the check the status of the exterior alarms.  This node will return either “on” or “off” and we’ll send that payload into a switch node.

You might have noticed I skipped a node there, we’re going to circle back around to that at the end.

If the current status node returns on, this sequence it disarms the alarm using the input_boolean.turn_off service and then outputs the message “alarm disarmed” in text to speech using the text to speech node in node-red dashboard.  This text to speech node outputs whatever is in the msg.payload of the message object which could be a string of text or an mp3 audio file.

If the alarm was off it starts the process of arming.  To start this process I set 3 variables with a single change node.  I set msg.payload to “Arming in 45 seconds” so the text to speech node will say it, I set msg.keypad to “arming” which will be displayed on the keypad, and I set the flow wide variable “arming status” to arming.

Next the message is passed into a delay node, which holds the entire message object for 45 seconds before passing it on.  After 45 seconds it passes into a switch node that checks to make sure the flow wide variable “arming status” is still equal to arming, and if it is, it activates a call service node that turns the exterior alarms on.  The other branch sets that flow wide variable “arming status” back to “not arming”.

If you’re following along at home you might be really confused as to why I’ve made this arming status variable.

Lets say you set the alarm and it starts arming, and then you decide you don’t want it arm you would have to wait 45 seconds for it to arm and then turn it off, which is totally unacceptable to me.  In order to fix this we’ve got this “arming status” variable.

The first switch variable that we skipped over checks that flow wide arming status variable.  It doesn’t matter where in the flow a flow wide variable is set, we can always read it.  If we punch in our pin while the alarm is in the process of arming our message gets sent down this other path where it sets “arming status” to “not arming” which then prevents the alarm from being set after the delay node.

The other problem with our delayed arming is that our status window is going to get out of sync.  For this we use a trigger node.  A trigger node sends a payload immediately, then sends a second payload after a specified amount of time.  The first payload I send will be “cancelled” to give the user some feedback that the pin was entered successfully, and then after 3 seconds it will set the status to “off” which is the current state of the alarm.  Because my alarm status window is set to display msg.keypad and not msg.payload I have to have another change node here to shift msg.payload into msg.keypad.

The last thing to consider when using flow wide and global variables is that since they are used to recall things that have already happened any restart of node red will cause them to not have any value associated with them.  This causes a problem where a reboot of node-RED leads to flow.arming status variable not existing, which would prevent anything from passing through this switch node.  We can solve this in two ways:  We can either create a new fork in our switch where flow.armingStatus is null (which means that the variable hasn’t been given a value yet), or we can give it a default value any time node-red starts up.  To do this, we will use an inject node, inject nodes are mostly used for debugging, but by clicking this “inject once after X seconds” check box you can have them run once whenever node red restarts ensuring that your flow and global variables will have default values.

Now all that’s left is to check out our new UI.  To access it you point your browser to your normal node-red URL, but instead of the “pound flow” part, you replace that with ui.  You can access this url from a tablet mounted on a wall to make a pretty slick home control hub and alarm panel.  Lets see it in action.

If you didn’t know this, I’m a high school teacher and we’re in the first week of summer!  What this means for you is I’ve got a lot more time to finish up all of the videos that I’ve been working on.  Make sure you hit that subscribe button because in between my normal Wednesday videos I may be releasing additional tutorials.  Coming up this week:  Automating remote backups for both hassio AND node-RED.  I’ve got a few user submitted sequences to include in my last Node-RED how to video, go ahead and post a comment if you’ve got anything else that you absolutely want to see included.  And as always, thanks for watching the hookup.

Links

Node-RED Palettes:
node-red-contrib-alexa-local
node-red-dashboard

Node-RED Flows:
https://github.com/thehookup/Node-RED-Examples/blob/master/Alexa_Local.json
https://github.com/thehookup/Node-RED-Examples/blob/master/security_panel.json

Get started with Hassio:
https://amzn.to/2KOpeNN
https://amzn.to/2kiLKTN

Support my channel:
Patreon: https://www.patreon.com/thehookup

Twitter: @TheHookUp1
Music By: www.BenSound.com

Related Posts