The HTTPd plugin has been out for a while, and is very useful for simple webhooks such as setting trigger variables from IFTTT. Recently a user asked for support for more complex actions to support the Netatmo's API which uses webhooks to push camera events. After developing a simple implementation to meet that user's needs I decided to create a more complete solution.
First, the authentication for the HTTPd plugin has been made more flexible. The plugin supports no authentication (leave the username/password field blank), Basic Authentication (as before), or Digest Authentication. By default both Digest and Basic are enabled, with Digest preferred. The plugin can be set to require Digest (no Basic authentication). For HTTPS connections, single certificate files (as created for self-signed certificates) and separate certificate/ private key files (as generated by Let's Encrypt) are supported. Some webhook clients may not work with self-signed certificates.
The most significant upgrade is that the plugin now supports POST requests with arbitrary payload data. If the payload content-type is "application/json", then the plugin converts the payload to the Python data structure. Other content-types can be supported, just create an enhancement request on GitHub. Requests using the new "/webhook" action provide the data payload, request URL key-value pairs, and the complete request headers.
Unlike the original "/setvar" command, "/webhook" does not create/set Indigo variables. Instead, the plugin broadcasts the complete data set using Indigo's broadcastToSubscribers() function. The payload of the broadcast message will look something like the following, which is a complex IFTTT recipe hook.
- Code: Select all
{
'request':{
'path':'/webhook',
'client':'100.24.12.106',
'command':'POST',
'headers':{
'content-length':'43',
'x-newrelic-id':'VwAOU1RRGwAFUFZUAwQE',
'connection':'close',
'x-newrelic-transaction':'PxRRVVRTAVEBVlgGBgADVkYdUFIOFQZOEgQLBw4NUVcLUF9YBgRXUFQUG0MHUwoLBAcDAxVs',
'host':'vmp.strangled.net:5566',
'content-type':'application/json',
'authorization':'Basic aG9va191c2VyOmhvb2tQYXNzMTAx'
}
},
'payload':{
u'value3':u'44',
u'value2':u'55',
u'value1':u'33'
},
'vars':{
'maker':'true'
}
}
At this time, I've tested the new functionality with IFTTT, Twilio, and Rachio. I am successfully capturing the webhook push notification from Rachio in a modified version of the Rachio plugin. I will be updating that plugin to use the push notifications instead of polling.
Here's how a plugin that wants to support webhooks does its setup. You must have the HTTPd plugin installed and configured first.
In the startup code for you plugin, register for the webhook messages:
- Code: Select all
httpd_plugin = indigo.server.getPlugin("com.flyingdiver.indigoplugin.httpd")
self.webhook_info = httpd_plugin.executeAction("getWebhookInfo", deviceId=0, props={u"name": self.pluginId}, waitUntilDone=True)
self.logger.debug(u"getWebhookInfo: {}".format( self.webhook_info))
indigo.server.subscribeToBroadcast("com.flyingdiver.indigoplugin.httpd", self.webhook_info["hook_name"], "checkMessagesHook")
The second line gets data from the HTTPd plugin that you need to configure a webhook.
Change "checkMessagesHook" in the last line to the name of your function that will get the broadcast messages. It takes one argument, which is a Python dictionary with the payload data (see above). Example:
- Code: Select all
def checkMessagesHook(self, hookData):
self.logger.debug(u"checkMessagesHook - hookData: {}".format(hookData))
self.checkAllMessages()
You'll need to use the info in self.webhook_info to configure the webhook on the service. For Twilio, this is done something like:
- Code: Select all
webhook_url = self.webhook_info.get("http", None)
number.update(sms_url=webhook_url, sms_method = "GET")
For Rachio, it looks like:
- Code: Select all
webhook_url = self.webhook_info.get("http")
url = (API_URL + "notification/webhook").format(apiVersion=RACHIO_API_VERSION)
data = {
"device" : {"id": dev.pluginProps["id"]},
"externalId" : dev.id,
"url" : webhook_url,
"eventTypes":[{"id": r[u'id']}]
}
self._make_api_call(url, request_method="post", data=data)
If you set up the webhook manually, you can log the contents of
- Code: Select all
self.webhook_info
- Code: Select all
http://username:password@your.ddns.net:5565/webhook-com.flyingdiver.indigoplugin.twilio
Discussion of this approach is welcome. The new plugin version that supports this functionality is available on the GitHub page as a pre-release. https://github.com/FlyingDiver/Indigo-HTTPd/releases