Last updated November 16, 2016: In a recent blog entry I told you how we’d been playing with Amazon Echo (Alexa) and got it working. Well, nearly. It turns out that what SEEMS obvious in the system is not all it seems - but read on as we've had success.
What is Alexa?
Actually the device is called an Amazon Echo – or for the cheap version and Amazon Dot. It is a box requiring power and WIFI that you can talk to and which will control things. It can automatically discover certain (and often expensive) commercial devices, it can play music, it can answer questions, set diary appointments, make shopping lists – all by voice. And with a little effort can talk to Node-Red to open up a whole new world of DIY possibilities.
Listening for specific words
For example in the Amazon setup pages, you can define variables that will only accept a certain amount of options – so for example – you might say “Alexa, tell computer to turn kitchen lights on” where “lights” could be, say, light, lights or heater.
And that’s fine – but you can’t TRUST that. the word “flights” works equally well and Amazon makes it clear in their documentation that you must do your own tests – any similar valid word in the dictionary could have been accepted (which seems utter madness to me but there you go). Indeed when we tested this – we found all sorts of irregularities – there is no way to say “accept ONLY these words”. And, if you say something that is not at all acceptable, the system will wait to time out – and that takes several seconds – which would annoy the hell out of the spouse. So – if you’re going to have to do your own checks anyway, we reasoned you may as well just try to get the basic words out of the units into Node-Red and “do your own thing”. To be clear then, the Amazon unit is no-where near perfect at word recognition and you have to consider that when designing a solution. I wonder if Google will be better.
A slight diversion here: If ALL you want to do is turn things on and off with Alexa and Node-Red – you COULD just ignore the rest of this article and go grab node-red-contrib-wemo-emulator or read other posts here describing my modifications to FAUXMO.
No – REALLY – drop it in – give it a name – like Orange – and define topics and payloads (which might go off to, say, MQTT or may be used to trigger direct port control on a Raspberry Pi or similar) for each of the two commands ON and OFF. Tell your Alexa to go looking for devices – it will find orange – and THAT IS IT – no HTTPS, no NOTHING. It really doesn’t get any easier. But only ON and OFF which is a bit restrictive - and for heaven's sake don't use the word "shed".
How about controlling your TV. Well, the Anymote Smart controller for Android will talk to Alexa and then hence control stuff by infra-red – except I can’t get it to talk to Alexa. I’ve written off to the guys at Anymote and will report back. But that takes care of all sorts of Infra-Red stuff as long as you leave your phone on! Not ideal really.
The Bigger Picture
And now – back to the bigger picture!
Before Alexa, all Aidan and I wanted was something that would listen to requests and then fire speech out so we could handle it ourselves in Node-Red – and that is exactly what we have now achieved. Some will shrink in horror at this having already done it another way – but it looks to us like a great general way forward provided you’re happy with writing your own simple, high level code to handle a sentence like “kitchen lights on” which could be as simple as a string comparison.
What we’ve done here – is to simple make Alexa collect up to 15 words (arbitrary number) after “ask computer to” – where “computer” is whatever word you want to be (the “skill”) and put them in an array, that function above, called “Alexa” does all of this and strips out words like “eh” “and”, “please” etc. – and you can add more exclusions. If you forget to actually say anything – the second output of the Alexa function handles it all for you automatically.
So in USER FUNCTION – you get an array – msg.word – with up to 15 lower case words – with the rubbish stripped out. You also get msg.combined, a simple string with everything in one string. If your requirements are simple – the latter might be the way to go.
If you merely want to have Alexa repeat the salient points of what you said so that “Alexa tell the computer to turn the lights on” – the output will be “you said: lights on”
“Alexa tell the computer to turn the lights on”
So above, Alexa reads the words in purple and passes on the rest. The simple Node-Red Alexa function strips out the words in red – and passes on the remainder in both an array of words and a simple string.
So clearly you might want that USER function to have outputs for MQTT and EMAIL and whatever other stuff to control your kit – that, of course, is easy and up to you. If you have 2 outputs from the function (set the number of outputs at the bottom) you can write to both at once – or separately by returning an array of messages - or just one and a null etc. When you send a null – nothing goes out.
Now – I don’t want to go TOO heavily into this because simply string comparisons is probably not the way to go for any kind of sizeable setup… but here is something I’ve used as a test and it absolutely works a treat.
The code in the user function (note the extra output) is trivial to say the least.
In the example above, I have the function react to “Alexa tell the computer to turn office lights on” by sending an ON command via MQTT to one of my ESP8266 boards. Off has a similar effect, different parameter. The final command it just a bit of fun.
Really – so to get all of this fun, you have to set up your SSL (which I found incredibly painful but in retrospect it was dead easy – another of life’s hurdles out of the way) so that Amazon’s servers can talk to a secure connection (your Raspberry Pi or whatever you are using – FriendlyArm Neo or similar would be just as good running Debian), you need to update some stuff into Amazon’s site – and from there on you never touch the Amazon site again –which is of course the point really - you only have to concern yourself with your USER FUNCTION in the cosy and quick-to-alter Node-Red environment. What you do with that is up to you. In my case I’ll add another output to go to MQTT and whatever comes in is processed and maybe does something – any message in msg.payload (you HAVE to send something back) is spoken by Alexa when you’re done. It really doesn’t get a lot easier.
In a really trivial case you might, with TWO outputs, (the first should be used to return a message;
Ok, I know, create another object and send them both out at once – I’m trying to keep this simple.
But of course, in reality, you’ll be likely to do FAR more than this and hence having the separate words in an array is useful.
So - on Amazon - you need an intent!
and a "sample utterance"
All we’re doing here is telling Amazon, for the “intent” “computer” – to collect up words and fire them off. And that's it for the Amazon end apart from the usual details they need about you and the https address of your website (the node-red exposed point).
As for Node-Red itself - the example above:
We have an http node which has nothing more than POST and “/echo” as the URL - then our ALEXA function contains the following - it may well be far from perfect but for now it works.
Note I've added a check for the word "cancel" which simply returns nothing, immediately. This is a vital addition as sometimes you just talk gibberish and want to get out of it!
The format response function looks like this…
The other blocks don’t have anything in them – other than the user function in which you can make use of msg.combined and msg.word. When you are done be sure to send the message out – payload containing text of your choice – as Amazon does need a return value even if your text is blank.
Set up an Amazon account – get PRIME if you want their music – if you’re rich get a Spotify account as the Amazon music selection is naff.
Get HTTPS so the end point of your Node-Red page (no real page exists) in my case http://whatever.com/url
That domain or subdomain needs to point to your building – and your router should redirect port 443 (ssl) traffic to port 1880 on your PI or whatever you are using. Why 443 - isn't that a pain for routers which have SSL management and VPN - yes it is - you have to move those to another port. WHY Amazon absolutely insist on port 443 for SSL I don't know - because any port will work but they won't accept them - please by all means do take it up with them.
If you have passwords set up on your Node-Red and your Node-Red UI (which I do) you’ll have to pass them in the Amazon website string – and I recommend you do this as clearly you don’t want any old Tom, Dick or Harry logging into your Node-Red
Once they are set up is a matter of going to the Amazon developer site with your account – the Alexa tab, setting up s skill including letting it know about your URL – filling in the bits above – and soon thereafter your DOT or ECHO or whatever you are using should be sending text over to you – to do whatever you want with.
Clearly, this will develop – splitting text up into words like this is useless for email addresses – so “Alexa tell the computer to send an email to email@example.com” is simply not going to work – and as for “Aidan” – it makes a complete mess of that
For reference – we made up some notes from our efforts to get an SSL certificate – if you have proven, better ways that cost less and don’t involve re-signing on every now and then as some freebies do – and which you know Amazon will accept as genuine – by all means give us blow by blow info. If you have a better, more complete, simpler description – please do let us know.
From our notes on setting up SSL – https – which may or may not be useful…
You need a trusted certificate to work with Alexa if you want it to talk to your Node-Red setup. Aidan has emailed the Amazon developer guys and eventually got a reply to say they had an issue with self-generated certificates, now resolved - sadly my router setup appears ot have an issue with them and so I can't test this (the router setup in Spain simply WILL not pass through port 443 to an internal unit).
With Node-Red typically you would have separate username and password for external access - this can be re-used with https: and the https: url can bypass the username and password requirement which means you can continue to use UI (dashboard externally).
Obtain SSL from – in our case, https://www.ssls.com
So, the procedure is to pay your money and then use openssl to generate a certificate request (.csr) file.
openssl req -out my.domain.name.csr -new -newkey rsa:2048 -nodes -keyout my.domain.name.key
Enter all the details that are asked for, but when it comes to the ‘Common Name (e.g.server FQDN or YOUR name)’ bit, you must put in the domain name of your server (without the ‘www’ as you get that anyway), so enter ‘my.domain.name’ into the ‘common name’ section and you will be verified for my.domain.name and www.my.domain.name’
Before you start the above process, make sure that you can access your Pi (or whatever) externally using your domain name to avoid unnecessary delays.
When you have your .csr, then edit it and cut and paste the full certificate request into the ssls.com request box when it asks for a certificate request.
It will then generate a small text file for you to place in the www/html root of your Pi. Make sure that you can access it externally by cutting and pasting the file name into a web browser, such as http://my.domain.name/AB5678DEF.txt (or whatever the file name is). When you enter that into a browser, you should see the contents of the file appear.
When you’re happy that works, then click continue on ssls.com and it will verify your website and generate your certificate and bundle which you can then get by clicking ‘download’ to get a zip file.
Store this all safely (including the private key file that you generated with the .csr file) – i.e. make a backup!
You can use a subdomain - so that if you use www.fred.com for something else you can have https://mysub.fred.com for Alexa and Node-Red (verified – I am using a “things” subdomain without issue while my basic root www address is going elsewhere).
Using advanced DNS or similar function with your provider, point mysub.fred.com to your site. In your router, take 443 and point to the 1880 port of your node-red Pi.
We checked and you definitely can’t use anything other than port 443.
Temporarily route port 80 (website in our case) to Pi - as you'll be asked to dump a file in the root folder for verification..... once complete this can be restored to whatever you were using it for in the first place.
Some files need to go into a folder i.e. /home/pi/ssl (our choice) and your info set up in node-red settings.js needs to know where they are...
Need to setup certificate in settings.js (https://... And uncomment ‘fs=’ …etc.
NOTE: I’ve just had to move the lot from one Pi to another – because I messed up the installation of the Pi and had no ports to play with. I can confirm – ALL that is needed is to move the certificate files (in any old directory) to the new Pi and make changes to the Node-Red settings file – uncommenting FS and adding two lines for the certificates - that’s it – all up and running – this is no-where near as complicated as I initially thought it would be.
Also, if your certificate isn’t from a root CA then you need to copy your base certificate into the certificate chain, mainly because node-red doesn’t give you any option to use a certificate bundle file. i.e. edit your .crt file, copy the contents and paste to the top of the ‘my.domain.name.ca-bundle’ file - this will add your certificate to the chain file.
Use SSL CHECKER https://www.sslchecker.com/sslchecker to check validity
Make sure that the certificate is verified all the way up to the issuing root Certificate Authority or Amazon will reject it
When all working - put your port 80 to where it was. After everything works - reboot your router to be sure.
And if I have not said it before – Amazon’s music library is SHITE!