Node-RED nodes for hubitat

Nah, not dumb at all. Just different than typical. There are lots of ways to do everything in computer-land. :slight_smile:

1 Like

Yeah but the atypical or clever stuff really bites you in the a** a few months or years down the line when you have to revisit it and can't remember why you took that approach.. Of course that's usually true with most of my prior code sadly... :rofl:

3 Likes

Months or years? I’m lucky if I can manage days and hours.

I’m pretty good with minutes though. :grin:

2 Likes

That looks like something I would like to try!
Which Google Home plugin are you using?
And how would I go about re-creating this?

I have a list of timestamps as part of an object in the msg.payload

This is a shortened list:

image

How would I go about comparing all the msg.payload.heapsOfNamesHere in 1 go, rather than manually entering each msg.payload.Mike's Computer and msg.payload.Temp Ensuite. etc.... I want to compare to a timestamp of now, for reference.

Also, possibly related question (in my googling for answers above). What is this called: msg.payload[0] and msg.payload[1].....I dont know what it is, so cant google it.

JSONATA perhaps? $each?

Here's a simple example you can adapt..

$each(payload, function($v, $k) {$k & ": " & $v})

I have run into a minor challenge that I am hoping someone can suggest a simple solution for. I have already started thinking about a complex solution inside NR, but am hoping I am missing something obvious that will simplify my approach.

Background
I have a virtual RGBW Light in Hubitat. Sometimes I want to change the brightness of the bulb from Hubitat. Sometimes I want to change the color of the bulb from Hubitat. I have a configured and well functioning hubitat to NR connection.

Control of the Brightness is via the Level state. Sure enough when I change the setting in Hubitat I get an output like this in NR:
image
Control of the color can be done in 2 ways in Hubitat (for the Virtual RGBW Light). Either Hue, Saturation, and Level (HSL) can be altered individually. Alternatively, there is a color picker. I am only concerned here about the color picker method.

When the color picker is used it sends NR 1-3 separate inputs. 1 each for Hue, Saturation, and Level (but only for the attribute that changed, though from the color picker, it is almost always either Hue only or Saturation and Level or all 3). From the NR side, it basically looks like 1-3 separate inputs that come in a random order and are indistinguishable from someone sending the inputs individually but really quickly.

For reasons that would be a whole other post, I don't care about the Level input when it is meant as a color change, but I do care about it when it is a Brightness change. I know technically, with a Hue, Saturation and Level triple different Levels are different colors, but for my purposes they aren't.

Challenge
I am trying to figure out how to know that a given level change is a brightness change and not a color change. The best I have been able to come up with is keep track of all 3 HSL inputs. If a L change comes in then hold it for some time say 100ms, then look and see if an H or S change came in within a window of 100ms before the L or 100ms after the L. If so throw it away, else treat it as a Brightness change.

Any suggestions would be welcome.

Side question/request
My initial guess was that it was the Hubitat side driver that sends them individually, but I guess I also want to ask @fblackburn if it is possible for the Hubitat node to output a single HSL attribute any time more than 1 changes, send a brightness attribute when only the Level changes and continue to send the individual attributes as is? I suspect this is a little to corner case to justify monkeying with the code, but thought I would ask since otherwise I am building some timing based work around.

You could try a join node. I think there is an option to set a time out and the number of messages to receive. (Create a single message from separate streams of messages : Node-RED)

1 Like

Another thought is testing for level change and storing the HSL values in a flow variable. The next level event test for a difference in H & S values if they are the same as previously stored then you know it's "brightness" uh, "lightness" changed. :wink:

1 Like

Because why not? @tmichael - Here is a very crude example of what I was thinking... hopefully I was understanding what you were going for..

The switch "property" is a JSONATA expression that evaluates to true or false...

($flowContext("hue") = payload.hue.value)
 	and ($flowContext("saturation") = payload.saturation.value)
	and ($flowContext("level") != payload.level.value)
	and ($flowContext("colorMode") = payload.colorMode.value)

It may still be a little buggy but you get the idea. My "Office Left Table Light" is a Sengled Color+ bulb using the Zigbee Advanced drivers. Also the 2 HE device nodes have the "all" attribute set and "send events" turned off.

The idea is to test for Level changes but everything else being the same. Also had to add a test for colorMode as switching between RGB and CT leaves the HSL values the same.

edit: might also want to add colorTemperature as a test / flow var too..

Being more a Javascript than JSONATA guy, I was thinking a function node, but otherwise this lines up with my thinking. The challenge is that sometimes a color change will come in as a Level change followed by a Hue change followed by a Saturation change. Without a delay built into the process, the level change will look like a brightness change if the evaluation happens before the hue or saturation change can update the flow variables.

2 Likes

So I was not getting that behavior with my testing. Of course I was using the "Set Color" (w/color map) and "Set Temperature" commands on the device page... so maybe there is something different going on. Easy enough to stick a delay in right after the HE device "level" node..

I like Javascript as well but JSONATA is pretty powerful for what it does and allows you to use the basic system nodes like Switch, Change etc.

1 Like

One other addition, you could also use this node maybe for a max delay:

You could also add device nodes with send events for "colorTemperature", "saturation" and "hue"..

I totally agree. I found that I had a complicated and detailed need at one point and jumped into JS for that. Once you are comfortable with 1, then getting equally proficient in the other feels like learning a second language unnecessarily. I respect people that try to stick with standard nodes (NR is a visual programming environment after all), but once I mastered the function node with JS hammer, I saw a lot of nails that it could care for. :grinning:

temp edit: I think I have a good solution, and will post it once I verify that it does what I want.

Shared solution at: https://community.hubitat.com/t/node-red-flow-samples-sharing/45207/573

1 Like

Cool! You might want to post it over on this thread:

JSONATA is like XPath/XQuery for JSON... it's a worthwhile skill to develop I think especially for streamlining things.. the other thing to consider is building it into a subflow... you can use HE node deviceID's for dynamic stuff.

Hi guys,
I am no developer.
I have started using node red a couple of month ago trying to be ready for Samrtthings taking away IDE. I was (and still) using Hubconnect to try and keep my Samsung AC units in sync with virtual switch and a virtual thermostat in HE. Had to use 2 devices as HE virtual thermostst is missing the switch capability.
With the help of @mavrrick58 I am now able to fully take advantage of Samsung Automation Studio pallet.
My question regards my need to keep my virtual devices and the "real" AC units in sync for the Switch, ThermostatMode, ThermostatFanMode, and CoolingSetpoint.
In practice, I am using the AC "real" thermostst unit and the Virtual switch and Virtual Thermostat (on a dashboard) to operate the AC unit. So, I might set the Coolong Set Point in each of them and would like it to be reflected in the other right away.
I have created 2 flows - one to update the "real" thermostat with changes initiated in the virtual devices and the 2nd for the other way around.
This sometime creates a problem. Say for example virtual thermostst cooling set point is 24 and I would like to change it to 22 and I have to go through 23. When node red sees 23 it will triger a flow to update the "real" thermostat to 23 and will trigger a change to the Virtual thermostat to 23 while I manually changed it to 22. Hope my explanation is understood.
I guess that this is something a developer deals with all the sime ......but I am no developer :roll_eyes:
Any ideas?
Can a flow run in a circle to avoid this?
Attached are my flows.


I generated a solution and posted in the sharing thread at:
https://community.hubitat.com/t/node-red-flow-samples-sharing/45207/573

2 Likes

Here is my original request
I have a list of timestamps as part of an object in the msg.payload

This is a shortened list:

image

How would I go about comparing all the msg.payload.heapsOfNamesHere in 1 go, rather than manually entering each msg.payload.Mike's Computer and msg.payload.Temp Ensuite. etc.... I want to compare to a timestamp of now, for reference.

Here was erkrek's answer

JSONATA perhaps? $each?

Here's a simple example you can adapt..

$each(payload, function($v, $k) {$k & ": " & $v})

This is where I'm up to currently
Thanks, that helped. I'm now at the stage where I want to compare the output. I've got the payload as an array, but I'd like to keep it as an object, since then I can use the name as the identifier.

How would I keep it an an object, so I can use the names? Or how do I compare it (as an array) to the key/names?

This is the output.
image

This is the expression in the change node.

image

You can change the output of $each to be an array of individual objects so something like this:

$each(msg.payload, function($v,$k) {{"name": $k, "value":$v}})

Then you would have a switch node or whatever that has this JSONATA expression to filter out the ones you want:

*[value < 0]

The idea here is to transform your original JSON object to a more ordered array of objects which you can then use JSONATA to compare against all values. If you wanted to see the "name" you can do something like this:

*[value < 0].name

note: use any JSONATA comparison expression - value < 0 is just an example!

1 Like

And of course you can combine the expressions...

$each(msg.payload, function($v,$k){{"name": $k, "value":$v}})[value < 0]
1 Like