Voice Controlled Home Automation using Amazon Echo, MQTT and NodeJS

2 Dec, 2018 | FeaturesTechVfd

I have a few power sockets that can be switched wirelessly, mainly Energenie devices triggered by my Raspberry Pi. I've had a web interface for ages, and some automation around things like sunrise/sunset, but I'd been meaning to add voice control to save me requiring a device to hand.

Obviously Alexa is hosted on Amazon's servers, so any command from the Echo was going to outside my own network. I needed to get it back inside, to trigger the code on the Pi, but I wanted to do that without exposing any URLs or potential data breach opportunities.

I found a few tutorials that showed how to do it by setting up your own Alexa Skill in AWS Lambda, combined with Amazon's IoT option, but this seemed like a lot of effort. Instead, I was trying to find the right combo of services that would knit together. In the end, a combination of IFTTT, Beebotte and a custom Node script running on a local machine did the job.

Integrating with Alexa

IFTTT was a simple selection as it already has Amazon Alexa listed as one of the services it integrates with.

A bit of research also highlighted the ability to accept and hit webhooks. So I could set up an Applet in IFTTT to listen for a command on my Echo and make a call to a URL that included a command.

To do that, simply select Amazon Alexa for the 'this' part of the Applet, then authorise integration. Once done, pick a "Say a specific phrase" trigger.

MQTT - Beebotte

Originally, the plan was to self-host a script to send a message via XMPP/Jabber when the URL was hit. I currently have a basic bot set-up by way of a Node script connected and listening for messages. Triggering a message using PHP seemed to be a bit of pain, so I turned to MQTT.

It was something I had been meaning to look into for a while and this proved a useful opportunity.

I didn't want to self-host. If I put it on my own hardware I was back to the issue of opening ports/making URLs accessible externally. I could have found somewhere to host software, but it would be much easier if I could find a third-party.

There are a few offering hosted MQTT services, but I needed one that accepted REST calls, and Beebotte did the job. Also nice that it has a free tier. If I make 100 calls a month I'll be surprised, so I didn't really want a service charging £5 a month.

After opening your account, you need to create a new channel, then a resource inside that channel. You'll also get a token unique token to access these.

Note that in their API docs, if you're not using one of their libraries, which you won't be, you simply substitute dev for your channel name/ref and res/res1 for resource name, i.e.

https://api.beebotte.com/v1/data/publish/<Your_Channel_Name>/<your_resource_name>

Something else that wasn't clear in the examples in their docs is that you don't need to submit the token in a header, you can pass it as a parameter as well (which is good, as IFTTT can't pass headers):

https://api.beebotte.com/v1/data/publish/<Your_Channel_Name>/<your_resource_name>?token=<your_token>

For the "that" part of Applet in IFTTT select Webhooks, then put the URL you created by inserting your channel, resource and token values in the example above into the URL field of the webhook. Set the Method to POST. Set the Content Type to application/json, and then set the Body to:

{"data":"your message here"}

So when Alexa is triggered, IFTTT will publish the message to the channel in Beebotte.

The final piece - NodeJS

Having the message there is fine, but you want to use it to trigger an event. In my case, I had a little internal API that was already set up to make my Pi transmit to my various Energenie sockets.

I already had a script that watches XMPP for messages, and this isn't very different. I used the mqtt module and a modified version of the example in Beebotte's docs:

https://beebotte.com/docs/mqtt

The main difference was I wanted to connect to the TLS version, for added transit security, so amended the connection to:

const options = {
port: 8883,
host: 'mqtts://mqtt.beebotte.com',
username: '<your_channel_token>',
password: '',
rejectUnauthorized: false,
keepalive: 60,
reconnectPeriod: 1000 * 1
};
const client = mqtt.connect('mqtts://mqtt.beebotte.com', options);

Note the change to the host as well (mqtts instead of mqtt).

When something is published to the channel, the Node script picks it up immediately and passes it through to my API, which then executes the relevant command.

A fairly quick and easy way to get voice control for your own projects without opening all the doors.