my.openhab.org REST API and Amazon Alexa Smart Home Skills
If you have an Amazon Echo with Alexa, and you make your own home automation devices, then you will no doubt want to interface the two together and have a powerful voice controlled home automation system.
Well, if you use OpenHAB then it's easy.
First follow the instructions to add my.openhab.org to your existing working openhab controller -
https://my.openhab.org/docs
Next, create an Alexa Smart Home Skill and link it to your Amazon account with LWA (Login.With.Amazon).
https://developer.amazon.com/edw/home.html#/skills/list
Alexa requires OAuth2.0 authentication with a service to function, but it was easier to link to LWA rather than try to work out the intricacies of my.openhab.org, seeing as I know my credentials anyway.
https://developer.amazon.com/lwa/sp/overview.html
After you have created an account with developer.amazon.com, follow the instructions here:
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/steps-to-create-a-smart-home-skill
In the AWS lambda function.lambda_handler (I used python, but you can use JavaScript or Java too), for the event namespaces below:
if event['header']['namespace'] == 'Alexa.ConnectedHome.Discovery':
return handleDiscovery(context, event)
elif event['header']['namespace'] == 'Alexa.ConnectedHome.Control':
return handleControl(context, event)
You will write the handleDiscovery and handleControl methods and return the following:
return { 'header': header,
'payload': payload
}
Just define the header as shown in the example step-by-step skill adaptor example on the Amazon developer website and fill in your device details in the payload instead of the examples.
Now, the bit that you actually need to know.
How do you get the device details and states of your home automation devices through my.openhab.org and how do you control those devices?
When you ask Alexa to 'Discover devices', your handleDiscovery method will be called.
To get a list of all OpenHAB devices, make a GET request to :
https://<username:password@my.openhab.org/rest/items
To get just a known devices details do:
To get just a known devices details do:
https://<username:password@my.openhab.org/rest/items/Light_GF_Corridor_Ceiling
To get just the state of a known device do:
https://<username:password@my.openhab.org/rest/items/Light_GF_Corridor_Ceiling/state
This will return an XML response similar to this:
<items>
<item>
<type>GroupItem</type>
<name>myopenhab</name>
<state>Undefined</state>
<link>https://my.openhab.org/rest/items/myopenhab</link>
</item>
<item>
<type>GroupItem</type>
<name>All</name>
<state>Undefined</state>
<link>https://my.openhab.org/rest/items/All</link>
</item>
<item>
<type>SwitchItem</type>
<name>Light_GF_Corridor_Ceiling</name>
<state>Uninitialized</state>
<link>https://my.openhab.org/rest/items/Light_GF_Corridor_Ceiling</link>
</item>
<item>
<type>NumberItem</type>
<name>Weather_Temperature</name>
<state>10</state>
<link>https://my.openhab.org/rest/items/Weather_Temperature</link>
</item>
</items>
In the handleDiscovery method, find the items like "SwitchItem" in the XML and add them to the payload by name to build your list of devices that Alexa can control using ON/OFF commands.
Just look at the Amazon example code to see what the payload should look like.
Then, when you ask Alexa to turn something on or off, your handleControl method will be called.
This is where you send the ON or OFF to your device in openHAB.
Make a POST request to the device's specific URL:
https://username:password@my.openhab.org/rest/items/Light_GF_Corridor_Ceiling
In the POST body, put the plain text command ON or OFF
Make sure you set the Content-Type header to 'text/plain' or it won't work.
In the URLs, if your my.openhab.org username or password has '@' or '.' characters in it, then be sure to escape them using %40 and %2E respectively, as mentioned in this wiki:
Or, if you have issues with passing the credentials in the URL, then encode them as base64 and put them in the headers, like so in bold below:
Python example
import base64
post_data = "OFF"
post_header = { 'Content-Type' : 'text/plain' }
req = urllib2.Request(openhab_url, post_data, post_header)
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
req.add_header("Authorization", "Basic %s" % base64string)
response = urllib2.urlopen(req)
That's it.