Looking for help with a Variable Connector

Looking first at the overall problem I'm trying to solve, I have an App that wants to know if it's daytime or nighttime, and it needs to receive an event twice a day when that state changes.

I'm controlling a light, and want it in one of three states: on - full brightness either night or day; off during the day - fully off; off during the night - on at very low level, acting as a nightlight for the room it's in.

I have a switch that I'm detecting button pushes on, that's correctly plumbed through a

subscribe(theswitch, "pushed", pushHandler)

call, and pushHandler is correctly invoked to flip between on and off states. I've also got two rules set up in Rule Machine called Sunrise and Sunset, they correctly happen on time, toggling a boolean Hub Variable "NightTime".

As far as I can tell, I need a Connector added to the Hub Variable, I've done that but I'm not crystal clear on a few points:

  1. What sort of Connector do I want here, I've had best results with a Variable connector, see below for details.

  2. With a Variable Connector, the following input line allows me to select the Variable Connector:

input "nighttime", "capability.sensor", required: true, title: "Night Time Variable"

But I cannot determine what the subscribe() call needs to look like:

subscribe(nighttime, "what_goes_here??", nightHandler)

  1. How can I determine in the nightHandler() method whether the variable became true or false? Either finding it from the evt passed to the handler, or directly reading the Hub Variable seem like two options I have, but no idea how to do either.

The only attribute for a Variable Connector (actually any connector) is variable, so that is the answer to #2. Subscribing to that should allow you to interrogate the value when it changes. If you need the value in between events, use the currentValue method for the connector device and the attribute variable.

This actually does depend on the type of connector; here's a switch connector I made for a Boolean hub variable:

The "Variable" connector is indeed the most consistent, always the variable attribute and setVariable() command, though it can also be a bit confusing since you never know what the underlying variable type is. With a connector like mine above, you'd have to do something different (since it's a switch connector); for example, something like subscribe(theSwitchConnector, "switch", "mySwitchHandler"). On the other hand, the possibilities are more constrained (e.g., I have no idea what happens if you call setVariable("blaaaarrrf") on something that is supposed to be true/false; you can't get into that kind of trouble here).

I'd say there aren't any right or wrong answers to the "what type of connector should I use?" question as long as that type is the one you also use in your app and it's available for that type of variable (which, again, "Variable" is for any kind). If it's your own app and you know what you're doing, whatever works for you is fine; might need some explanation on exactly what is (or isn't) possible if you have other end users either way. :slight_smile:

On a side note, some day, I hope they make an hub variable API so we don't need connectors for simple cases where responding to events isn't necessary. Looks like you need the events for your use case and therefore need a connector (unless they really change something), but maybe some day we'll have something for the rest!

You should have an Event object passed to this handler. Presumably your code includes something like void nightHandler(evt) { ... }. In this case, evt.value would give you the new value. I suspect just reading it from the device, as suggested above, would work just as well, though this would avoid any issues where you might be dealing with a cached state (I'm not exactly sure how Hubitat optimizes these lookups but it does seem to happen sometimes) or if you have simultaneous execution of your app (say, two events that wake it up happen at nearly the same time; this would give you the correct value for each).

Got it all working, thank you @thebearmay and @bertabcd1234 . The one thing that initially caught me out and caused some "unexpected" problems was the fact that both evt.value and nighttime.currentValue("variable") yield String values, even though the Hub Variable was declared as a boolean.

Combine that with the fact that:

def foo = evt.value  // assume value is false.
log.debug("foo == $foo")
if (foo)
{
    // This code executes
}
if (foo == true)
{
    // This code does not execute
}

compiles and runs just fine, but produces really inexplicable results if you've incorrectly assumed that foo is a boolean rather than a String. groovy's type handling is going to take a lot of getting used to, coming at this as a 30+ year career C/C++ programmer. :smiley:

1 Like

Yeah, the type of the variable attribute on a connector of type Variable is always a string, regardless of the "underlying" type of the real hub or local variable. This is presumably to make it the most generally useful while still fitting into the valid Hubitat attribute data types (of which, say, Object is not one). So, you just need to be careful to only feed it valid data if you are manipulating it or to cast it to an appropriate type (or find some other workaround) if you're comparing it to other data.

And indeed, so-called Groovy truth is ... fun. :slight_smile: It can save a bit of typing sometimes, at least, I suppose!

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.