Tip: Calling Node Red HTTPS (or other webhooks) from Hubitat Elevation Rule Machine

Hi everyone,

As a n00b Hubitat user I have been wrestling a bit with calling my main HTTPS Node Red installation from a Rule Engine trigger. Now that I have it working someone else might benefit from the experience. I use Hubitat Elevation as a convenient bridge to collate events from (plentiful) ZigBee devices into Node Red.

Prerequisites

  • You need to have the latest Rule Machine installed, so update your Hubitat Elevation to latest version before you start this process.

Step 1: Install a "notification device" driver that can do an HTTPS submit
The standard Rule Engine HTTP GET does not have a flag to ignore SSL warnings, so I couldn't call my local instance of Node Red - it has a self signed certificate which caused enough SSL warnings to abort the request.

The driver code is below, all credit goes to Brian Johnson since I only added ignoreSSLIssues: true.

/**
 *  File: HTTP-Notifications.groovy
 *  Platform: Hubitat
 *  Modification History:
 *            Date        Who            What
 *    v1.0.0  2020-08-16  Brian Johnson  Initial version
 *
 *  Copyright (c) 2020 Brian Johnson
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

def version() {"v1.0.0"}

metadata 
{
	definition (
		name: "HTTP Notifications",
		namespace: "john3300",
		author: "Brian Johnson",
		description: "Send notification messages to an HTTP URL via GET",
		importUrl: "https://raw.githubusercontent.com/john3300/Hubitat-HTTPNotifications/HTTP-Notifications.groovy"
	)

{
		capability "Actuator"
		capability "Notification"
    capability "PushableButton"
	}

	preferences 
{
		input name: "httpUrl", type: "text", title: "Notification URL:", required: true
		input name: "queryString", type: "text", title: "Query String:", description: "Use <MSG> as placeholder for message", required: false
	}
}


def push(buttonNumber)
{
deviceNotification(message) 
}

def deviceNotification(message) 
{
// Sending message [device=LOUNGE_BUTTON&event=PRESS&pushed=5] to [https://192.168.1.110:1880/notify]
	log.debug "Sending message [${message}] to [${httpUrl}]"

/**
 * params options
 *
 * uri - The uri to send the request to
 * queryString - The raw, already-escaped query string.
 * query - Add these parameters to the existing query string. If any of the parameters already exist in the query, these values will not replace them. Multiple values for the same query parameter may be added by putting them in a list.
 * headers - Request headers
 * path - The path component of this request. The value may be absolute or relative to the current path.
 * contentType - The content-type used for any data in the request body, as well as the Accept content-type that will be used for parsing the response.
 * requestContentType - Assign a different content-type for the request than is expected for the response.
 * timeout (since 2.0.9) - timeout in seconds for the request, max timeout is 300
 * textParser (since 2.1.1) - possible values: true, false. If set to true, the response will be parsed as plain text, if false the system will attempt to determine the content type and parse the response into an object. Defaults to false.
 * ignoreSSLIssues (since 2.1.8) - possible values: true, false. Ignores certificate issues for SSL connections. Cert does not have to be from a trusted authority and the hostname does not need to be verified. This is primarily for dev situations that make use of localhost, build, and test servers. Defaults to false.
 */
	def params = 
[
		uri: httpUrl,
		contentType: "text/plain",
    ignoreSSLIssues: true
	]

	if (queryString) 
{
		queryString = queryString.replaceAll("<MSG>", URLEncoder.encode(message, "UTF-8"))
	    log.debug "Query String is [${queryString}]"
		params.put("queryString", queryString)
	}
else
{
	    log.debug "Query String is [${message}]"
		params.put("queryString", message)
}

	try 
{
		httpGet(params) 
    { 
        response -> if (response.status >= 300) 
        {
				log.debug "Received HTTP error ${response.status}!"
			} 
        else 
        {
				log.debug "Message delivered, response: ${response.data}"
			}
		}
	} 
catch (Exception e) 
{
		log.error "Error calling httpPost ${e}"
	}
}

Step 2: Install the Notifications app (may work without this step?)

  • Click on [Apps] and [Add Built-In App], scroll down to Notifications.

Step 3: Add an instance of HTTP notifier to talk to your Node Red webhooks (or your own webhooks)

You need to create an instance of a Virtual Device to do this, configured to point to your special URL.

  • Click on [Devices] and [Add Virtual Device]

  • In “Device Name” and “Device Label” put something like “Node Red HTTPS”.

  • In “Type” scroll down to the bottom to the “User” section and choose the driver you just added, called “HTTP Notifications”.

  • Click [Save Device] and the screen will refresh to show an additional field “Notification URL”

  • In “Notification URL” you just want to put the base of the URL, without any parameters. i.e. in the URL this is the part before the ‘?’ character. For example, in my case, it is “https://192.168.0.202:1578/node-webhook”. A full URL might look like “https://192.168.0.202:1578/node-webhook?sensor=GARAGE_DOOR&contact=open”

  • Leave Query String blank, and Click [Save Preferences]

Step 4: Install the zigbee device

  • Plenty of tutorials on how to do this so I am not repeating this here.

Step 5: Add a Rule to trigger when something changes

  • Click on [Apps] and [Add Built-In App], scroll down to “Rule Machine”.

  • Click [Create New Rule]

  • Put a title in, something like “GARAGE_DOOR changed”

  • Click [Select Trigger Events]

  • In “Select capability for new Trigger Event”, choose a kind of event to match the device you are adding. In my case this is “Contact” because it’s a contact sensor. Press [TAB] to refresh the screen once you have selected one (if it doesn’t automatically refresh the panel).

  • Where it says [Contact Sensors * Click to Set] click it and choose the sensor you want to trigger events from and click [Update]. It will show every sensor you have with that capability. In my case, I ticked my previously defined “Contact Sensor - GARAGE_DOOR”.

  • Under “Contact reports” set it to “Changed” since we want to pass ANY change to Node Red. Click [Done with this Trigger Event] and then [Done with Trigger Events].

(for more complex sensors that can have many different events I would add all of them here as triggers so no matter what happens to the sensor you can send them all to Node Red if you are using the Hubitat Elevation as a simple bridge).

Step 6: Add a local variable to use as a URL parameter

You need to do this, because strangely you can’t use device attributes as %parameter% in the URL, only variables.

  • Click on [Create Local Variables] and [New Variable]

  • Type in a name for the variable and hit [TAB], in this case I used “contact” and selected String because it contains a word. For things like temperature sensors, just use Number. Initial value is optional, since it will be overwritten the moment an event comes in.

  • Add a local variable for each attribute you need to pass to Node Red from the sensor, then click [Done with Local Variables].

Step 7: Create an action to copy physical device attributes into Local Variables.

  • Click [Select Actions to Run], [Select Actions to Add], [Set Mode, Variables or File, Run Custom Action] and [Set Variable].

  • In [Select Variable to Set] choose the variable you have defined and in [Select string operation] which appears, choose “Device attribute”. Select the device you used in your previous trigger (in my case it is “Contact Sensor - GARAGE_DOOR”) and click [Update] and choose the attribute you want to copy into the Local Variable (in my case it is “contact” but I might also pass the battery reading as well at some point soon).

  • Don’t put any delay in there – in an IOT system your worst enemy is delay!

  • Click [Done with this action]

Step 8: pass notifications from the device to Node Red

  • Click [Select Actions to Run] or [Select Actions to Add] depending which screen you are on and [Send, Speak or Log a Message, Send HTTP Request] and then [Send or Speak a Message]. If you don’t have “Send or Speak a Message” available, you probably have to update your Hubitat Elevation version to get the latest Rule Machine codebase.

  • In [Message to Send] put the parameters for your URL here (i.e. everything after the ‘?’) e.g. in my case it is “sensor=GARAGE_DOOR&contact=%contact%“. Notice that the parameters I am sending through all come from Local Variables whenever you use the % symbol – we defined the “contact” variable earlier.

  • Under [Select notification devices] choose your virtual device “Node Red HTTPS” and [Update]. No delay!. Click [Done with this action] and [Done with Actions].

Edit: I wrote this up after the fact so if it works for you or instructions need to be changed/improved please comment below. Great to be able to call self-signed HTTPS endpoints directly without creating an HTTP=>HTTPS bridge.

Just curious - why not use MakerAPI and the Hubitat node to capture events?

2 Likes

+1 on @rakeshg's suggestion - @fblackburn's nodes are awesome. I have replaced all of my RM rules (and most HE apps) with NR sequences and it's been working great. The caveat being that doing this works for my situation/setup and ymmv.

2 Likes

+2 on what @rakeshg and @erktrek wrote. @fblackburn's nodes also permit receiving websocket events ....... if you don't want to control Hubitat devices via Node-RED.

Ah - was this the reason for not using the HE node/Maker API?

I am not familiar with MakerAPI however it seems like you need to constantly poll your Hubitat MakerAPI to see if any devices have had events recently. I want the opposite, which is whenever something happens in the Zigbee device grid, an event is triggered instantly in Node Red, not with a polling delay.

Also a few very good reasons I use Node Red for my core setup:

  1. Node Red is an order of magnitude easier to do really complex rule logic because it's drag and drop visual representation with plenty custom nodes that do exactly what you need. For example if you want to throttle events to no more than 5 per hour you just put a filter in a flow. Hubitat Elevation rule management is a somewhat tedious text based process of choosing something from a menu which then reveals more options which then reveal more options - everything pretty disjointed and text based so it's hard to visualise your solution.

  1. From what I can see the security of Hubitat Elevation is not appropriate for connecting to the external internet say for showing a dashboard. There is no password and you can't enable HTTPS easily. I'd question if you should have any passwordless service running inside your home network at all. It's only a matter of time before your old network connected fridge gets hacked while it is inside your home network. Node Red options for security are strong and you can go as far as you like to feel comfortable nobody is gaining access to your home control systems.

Having said that, Hubitat Elevation works great as a Zigbee bridge for me, now that I know how to bridge via HTTPS into my main system. Node Red can't do Zigbee & Z-Wave so easily. :wink:
My wish is that Elevation supports more of the cheap and common Ali Express Zigbee sensors out of the box instead of wrestling with 3rd party drivers as I've only had 50% success with those.

Welcome to the Node-RED party! There are a bunch of us here that do something similar with their setups. I am using NR as a rule engine and controller. HE provides device management and some key integrations.

Also you don't need to poll the Maker API - The HE Nodes connect to it (and HE) via a webhook. @aaiyar mentioned you also have the option to use websockets as well. Very handy!

@rakeshg already posted the NR link but here it is again anyway!

Also check out some of these threads..

1 Like

I'm still wondering if MakerAPI will work with his self signed cert NR config...

1 Like

Erm. Yes, there is.

http://HubIP/hub/userAdmin

1 Like

Yeah probably not.. :slightly_frowning_face:

I’m not sure either - normally, when configuring MakerAPI it is http but @mr.murraybrandon could try https and see if it works.

That’s HE security, right? The node works fine with that (I have it enabled)

Nope - as @erktrek said, there is no polling - it's pub/sub model as far as I know.

Yeah - I have all my automation logic in NR - basically, HE is being used for radios and MakerAPI (for Homebridge and Node-RED)

Me too. I was just pointing it out for OP.

1 Like

@gopher.ny Any way we could get this added to MakerAPI as an option?

2 Likes

If hub UI has a certificate set up, any app (including MakerAPI) can use https to access its usual endpoints with no additional development effort.

I think they mean outbound from Maker API:

Not sure if Maker API currently allows https there (I've never tried it) and possibly even if it did, it probably would choke at self-signed certificates on the target unless it had the ignoreSSLIssues flag set on the outbound requests.

3 Likes

Thanks for your comments everyone, I am sure this will give future IOT setups a good starting point of some options.

So a correction - yes you can require Hubitat Elevation to ask for a username and password, in Settings/Hub Login Security. I obviously didn't click around enough :wink: Does anyone know if it detects too many failed attempts (to stop brute force attacks) or can notify you of a failed login attempt?

I'll give MakerAPI a go at some stage once I complete my other little projects although I use my webhooks in Node Red to get device events from a few different sources, not just Hubitat Elevation.

No, but if someone is brute forcing your hub from inside your network, I'm pretty sure you have larger issues to deal with.

4 Likes

Kind of off-topic... I just want to do a "get" webhook to a service I use to deliver my Pocket articles to Kindle. I currently do this with IFTTT, but would prefer to not be reliant on it if it can be avoided. If there an easy way to send a get webhook via Hubitat?