Hue bulbs and groups

Thanks and sorry, this is probably really frustrating for you…this is the bit I just can’t get my head around and I don’t know why. As a learning experience it’s been great for me, it’s introduced me to so many new topics and methods that I’m pretty pleased so far, but it’s just a different way of thinking that I need that ‘eureka’ moment for it to fully sink in.

So, in my head…

  1. I’ve passed the GK rule all the info I need (groupname#onoff#brightness#colortemp):
GK GKCommand - gSpots_LR_All#ON#100#14
  1. I have added all items into the same group:
Group:Dimmer  gSpots_LR_All
  1. So that when I call
group.members.forEach[ light | deviceQueue.add(light) ]
  1. This is how I’m adding all members of that group into the deviceQueue:
Spot_GF_LR_1_Brightness
Spot_GF_LR_2_Brightness
Spot_GF_LR_3_Brightness
Spot_GF_LR_4_Brightness
Spot_GF_LR_1_ColorTemp
Spot_GF_LR_2_ColorTemp
Spot_GF_LR_3_ColorTemp
Spot_GF_LR_4_ColorTemp
  1. Where I am struggling is that I send the x_Brightness and x_ColorTemp items different values, in this case Brightness = 100 and ColorTemp = 14 but because I’m automatically filling the deviceQueue this way how do I differentiate between item to give it the correct command?

Hi,

Been reading through the thread and some relevant group based posts and I think it might be sinking in.

I get that I must pass everything / all the info to the deviceQueue outside of the timer, and the timer just polls each item in the queue and does something to it.

So, I need to append the command, (ie ON / brightness to 100 / colortemp to 14), to each group member. In the timer loop can then split the deviceQueue item and then send the appropriate command to the sendCommand(name,command) part.

So, unless someone can suggest I’m going down the wrong route…I need to work out how to filter the group into _brightness items and _colortemp items, append the appropriate command to them and then add them to the deviceQueue.

As I’m new to groups I’m reading the DP for it and docs and think that I might need to

group.members.filter [where the last part of the name = brightness ]  .forEach [ each one | 'append member and #command into one string' and 'deviceQueue.add(appended string)']

group.members.filter [where the last part of the name = colortemp ]  .forEach [ eachone | 'append member and #command into one string' and 'deviceQueue.add(appended string)']

Does that make sense?
Can you filter for a command like where name contains ‘brightness’? or do I need to do more work outside the groups.filter command?

EDIT

I’m currently here in my thinking

group.members.filter[ b | b.name.toString.split("_".get(4)) == "Brightness"].forEach[ bYES | bYES.deviceQueue.add(bYES + "#" + brightness)]

But the split part isn’t working, LOG

Rule 'GK Living Room Lights Brightness': 'get' is not a member of 'java.lang.String';

Right, getting somewhere slowly…

Group filter now works:

group.members.filter[ light | light.name.split("_").get(4) == "Brightness"].forEach[ bYES | deviceQueue.add(bYES + "#" + brightness)]

Timer routine:

    // Timer
    if(timer === null) 
    {
        timer = createTimer(now.plusMillis(delay), [ |
            if(deviceQueue.peek !== null) 
            {
                val light = deviceQueue.poll
                val lights = light.toString
                val lightSplit = lights.split("#").get(0)
                val lightSplit2 = lights.split("#").get(1)
                sendCommand(lightSplit,lightSplit2)
                logInfo(logName, "deviceQueue - " + lightSplit + lightSplit2 + " - SENT")
                timer.reschedule(now.plusMillis(delay))
            }
            else
            {
                timer = null
            }
        ])
    }

This also works…however, (there always was going to be a however :smile:)

The LOG shows that the item does not exist.

2020-05-01 13:02:15.388 [WARN ] [rthome.model.script.actions.BusEvent] - Item 'Spot_GF_LR_1_Brightness (Type=DimmerItem, State=100, Label=GF LR Spot 1 Brightness, Category=null, Groups=[gSpots_LR_All, gSpots_LR_B_These])' does not exist.
2020-05-01 13:02:15.397 [INFO ] [se.smarthome.model.script.GateKeeper] - deviceQueue - Spot_GF_LR_1_Brightness (Type=DimmerItem, State=100, Label=GF LR Spot 1 Brightness, Category=null, Groups=[gSpots_LR_All, gSpots_LR_B_These])0 - SENT
202

I assume that by splitting it into a val it needs to be converted back to something???

Doh, worked it out, I needed to add .name to the end of my forEach item…

Seems to be working now…going to have some real life testing and then I will post the whole rule if anyone is interested.

Also, just for future reference, I found this in the hue api text:

How many commands you can send per second?

You can send commands to the lights too fast. If you stay roughly around 10 commands per second to the /lights resource as maximum you should be fine.

For /groups commands you should keep to a maximum of 1 per second.

I’ve found that 1 per second is still a little unpredictable, so have set my delay to 1.5 seconds, which seems fine…I may work to trim this down and test but for now I’ll leave it where it is!

2 Likes

That’s one approach. There are others of course.

  • Just put the brightness Items into the Group and generate the name of the corresponding Color Temp Item
....forEach[ light | 
      deviceQueue.add(light.name+"#"+brightness)
      deviceQueue.add(light.name.replace("Brightness", "ColorTemp")+"#"+color)
    ]
  • Instead of passing everything as one String to the GK Item, put each type of Item in it’s own Group and call the GK Rule once for each Group
    // In the Rule that calls GK
    vLightsGatekeeper_Set.sendCommand("gSpots_LR_Switch_All#ON")
    vLightsGatekeeper_Set.sendCommand("gSpots_LR_B_All#100")
    vLightsGatekeeper_Set.sendCommand("gSpots_LR_CT#14")

This is the approach I would use as it keeps the GK Rule very generic.

You have a misplaced closing paren.

b.name.toString.split("_").get(4) == "Brightness"

That’s very helpful information. You should be able to get it down to 100 msec between commands according to this as long as you are not commanding Hue Grouped lights (not to be confused with openHAB Groups).

Hi,

It’s all working well at the moment, I like your alternative forEach addition. I may try that out a bit later.

Found some more info on the Hue REST API

‘Depending on the size of your Zigbee network commands to the API. Larger networks may require up to a second between commands.’

1 Like

Hi,

I’ve completely re-written my rules again :slight_smile: This time I think the penny has dropped, I’ve changed it so that all the work is done in the lights.rules and then the GateKeeper.rules is kept generic so I can use it elsewhere. I now get it!

The process now simply send the GK dummy variable that stats the rule an (itemname#command), which the GK rule splits and then processes accordingly, (sorry it’s taken this long to get to where you started @rlkoshak!)

I’m just tidying up the rules and then I’ll post them all for history as a learning experience.

One thing that I can’t seem to get to work is that I have 2 colour bulbs that accept HSBType commands, ie (hue, saturation, brightness), or (100,50,100) or whatever.

I’ve tried various things to set it into a HSBType in both lights.rules and in GK.rules. AS I have to send the GK the command 100,50,100 as a string I assume it needs to be split and then converted in the GK rule, (which isn’t perfect as it makes it less generic but so be it if it has a couple of if statements in there over time)

I’ve tried various including:

if(GKItemCommand.toString.split(",").get(2) !== null)
                {
                var DecimalType hue = new DecimalType(GKItemCommand.split(",").get(0))
                var PercentTypeType sat = new PercentType(GKItemCommand.split(",").get(1))
                var PercentType bright = new PercentType(GKItemCommand.split(",").get(2))
                var HSBType GKItemCommand = new HSBType(hue,sat,bright)
                }

ie all commands I send it are one number, if I send it one with 100,50,100 if the 3rd split 100 isn’t null then create a new HSBType item to pass to the sendCommand…

However it doesn’t work…This particular code threw the log error:

2020-05-03 13:04:30.233 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 61 2020-05-03T13:04:30.205+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@daf97f (conditionalExpression: false)

But there have been others, including:

2020-05-03 12:27:39.559 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert '-1' to a command type which item 'Spot_GF_LR_7_ColorTemp' accepts: [PercentType, OnOffType, IncreaseDecreaseType, RefreshType].

Which suggests to me that I’m just not getting the HSBType right for the item to accept…I get the feeling I’m just making it far more complicated that I need to.

Any ideas?

I like the idea, but think you have to implement slightly differently.
get(2) will blow up when there is no (2), rather than gracefully return null
You could see if the length of the array was >2 instead.

Details, details. Are you meant to be making three variables here, not defining the same one ‘hue’ three times? And that type?

Hi, yes…sorry hue should be hue, sat and bright variables…typo (have updated the OP).

Like the idea with the >2, that will work properly.

That part isn’t the main issue as I’ve tried sending it just full HSB commands to make that part irrelevant while testing, it’s the HSBType conversion / sendCommand that is my main struggle.

:smiley:

That particular error is coming from inside the Timer. So the code you posted is inside the Timer block? I’m just trying to get oriented. One important thing to understand is that we are using the sendCommand Action. The sendCommand Action only accepts two Strings as arguments. Even if you pass it the “real” Item as the fist argument and an HSBType as the second argument, it’s going to convert them to Strings anyway. Since the GK Rule is receiving the command and Item as a String already you really are not accomplishing much by trying to convert that String to an HSBType because it’s just going to become a String again anyway.

So any messing with HSBType should be in the Rule that calls the GK Rule. In that Rule you already know what the three numbers are, you just need to format them into the correct String format. There are two ways you can do it:

  1. Build the HSBType and then call toString on it
val newColor = new HSBType(new DecimalType(100), new PercentType(50), new PercentType(100))
vLightsGatekeeper_Set.sendCommand("gSpots_LR_Color#"+newColor.toString)
  1. Just build the String and send that. The format is just “hue,sat,bri”.
vLightsGatekeeper_Set.sendCommand("gSpots_LR_Color#100,50,100")

There is no reason to parse out the HSB stuff to built an HSBType only to have it converted back to a String.

Though I might be missing something. Post your current code if what I say above doesn’t make sense.

Hi,

What you’ve said is about where I am…I know that my error is that the color item is expecting a HSBType command to become a colour.

The problem I have is exactly as you say, the item gets converted into a string along the way.

vLightsGatekeeper_Set.sendCommand("GF_LR_Lights_Color#100,50,100")

This reaches the GK rule, which adds it to the queue and then loops through the queue with the timer. Inside the timer it just splits the sendCommand received:

ItemCommand = GF_LR_Lights_Color
What to do = 100,50,100

It then does a send command for the actual item

sendCommand(ItemCommand,What to do)

or in actual OH terms:

sendCommand(GF_LR_Lights_Color,100,50,100)

But when this runs through is where I get the log error:

2020-05-03 12:27:39.559 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert '100,50,100' to a command type which item 'Spot_GF_LR_7_ColorTemp' accepts: [PercentType, OnOffType, IncreaseDecreaseType, RefreshType].

So, it’s saying that it doesn’t accept the 100,50,100 part of the command as it’s not the correct type.

What I don’t know is where / if / how I need to tell it that it is a HSBType command or how to convert it to one from the string it has become…

Does that make sense?

That’s four parameters. sendCommand wants two, an Item name, and a command. Your command as a single string might look like “100,50,100”

Yes, so how do I send it 100,50,100 as one string? I’ve tried 100,50,100 in " " and ’ ', tried converting it to a HSBType on its own, confirmed its a string and from HSBType back into a string.

I’m sure it’s simple and I’ve just gone around the actual answer…

I’m guessing that the var I create to start with in the lights.rule is just a string as that is what the sendCommand needs to send it to the GK.rule, the GK rule just splits the command by the # and then has the item and command it finally needs to send. So, do I need to tell it that it is a HSBType then or confirm it is a string…what is the format that item / channel is expecting me to send the HSBType command?

From your earlier post. HSBType or ColorType or whatever it is,is not listed.

This Item is not of Color type, I am guessing?

How?

The original Rule, which I thought you went back to does something like the following:

val itm = receivedCommand.toString.split("#").get(0)
val cmd = receivedCommand.toString.split("#").get(1)
sendCommand(itm, cmd)

So when you send it “GF_LR_Lights_Color#100,50,100”

  • itm == "GF_LR_Lights_Color"
  • cmd == "100,50,100"

Notice, both are Strings (have quotes around them). And cmd is of the correct format to be sent to a Color Item.

How are you getting to sending the actual numbers as multiple arguments to sendCommand?

OK, that error means something different. You are trying to send an HSBType command to a ColorTemp Item which is a Dimmer Item. You can’t send an HSBType to a Dimmer, only to a Color. It’s the Item that is wrong, not the command.

HI,

Fixed that one but I think that was a by-product of something else as I’m getting more errors:

Lights.rule:

rule "Select Spotlight Scene Rule" 
    when
        Member of gLights_Scenes received command
    then
        val caseItem = triggeringItem.name.split("_").get(3)
        logInfo(logName, "caseItem - " + caseItem)
        val caseValue = triggeringItem.state
        logInfo(logName, "caseValue - " + caseValue)
        var caseONOFF = OFF
        var caseBrightness = -1
        var caseColorTemp = -1
        var caseColor = -1

        if(caseValue == OFF)
        {
            caseONOFF = OFF
            caseBrightness = 0
            caseColorTemp = 0
            caseColor = 0
            logInfo(logName, "OFF - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
        }
        else
        { 
            // Run the Spotlight Scene Selector
            switch caseItem {
            case "All" : {
                // Settings for ALL LIGHTS
                caseONOFF = ON
                caseBrightness = 100
                caseColorTemp = 14
                //caseColor = 0
                logInfo(logName, "ALL - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
            }                               
            case "These" : {
                // Settings for THESE LIGHTS
                caseONOFF = ON
                caseBrightness = 100
                caseColorTemp = 14
                //caseColor = 0
                logInfo(logName, "THESE - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
            } 
            case "Sofa" : {
                // Settings for SOFA LIGHTS
                caseONOFF = ON
                caseBrightness = 100
                caseColorTemp = 14
                //caseColor = 0
                logInfo(logName, "SOFA - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
            }    
            case "Those" : {
                // Settings for THOSE LIGHTS
                caseONOFF = ON
                caseBrightness = 100
                caseColorTemp = 14
                //caseColor = 0
                logInfo(logName, "THOSE - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
            } 
            case "TV" : {
                // Settings for TV LIGHTS
                caseONOFF = ON
                //caseBrightness = 100
                //caseColorTemp = 14
                caseColor  = "100,50,100"
                logInfo(logName, "TV - caseONOFF = " + caseONOFF + " / caseBrightness = " + caseBrightness + " / caseColorTemp = " + caseColorTemp + " / caseColor = " + caseColor)
            }
            }
        } 


        val group = ScriptServiceUtil.getItemRegistry.getItem("gSpots_LR_" + caseItem) as GroupItem
        logInfo(logName, "Lights Group - " + group)

        group.members.filter[ light | light.name.split("_").get(4) == "Brightness"].forEach[ bYES | vLightsGatekeeper_Set.sendCommand(bYES.name + "#" + caseONOFF)]
        group.members.filter[ light | light.name.split("_").get(4) == "Color"].forEach[ bYES | vLightsGatekeeper_Set.sendCommand(bYES.name + "#" + caseONOFF)]
            if(caseONOFF != OFF)
            {
                if(caseColor == "-1")
                {
                    group.members.filter[ light | light.name.split("_").get(4) == "Brightness"].forEach[ bYES | vLightsGatekeeper_Set.sendCommand(bYES.name + "#" + caseBrightness)]
                    group.members.filter[ light | light.name.split("_").get(4) == "ColorTemp"].forEach[ bYES | vLightsGatekeeper_Set.sendCommand(bYES.name + "#" + caseColorTemp)]
                }
                else    
                {
                    group.members.filter[ light | light.name.split("_").get(4) == "Color"].forEach[ bYES | vLightsGatekeeper_Set.sendCommand(bYES.name + "#" + caseColor)]
                }   
            }
end

GK.rule

rule "GateKeeper Rule"
    when
        Item vLightsGatekeeper_Set received command
    then
    // Add the commands to the Queue

    deviceQueue.add(receivedCommand.toString)

    // Timer
    if(timer === null) 
    {
        timer = createTimer(now.plusMillis(delay), [ |
            if(deviceQueue.peek !== null) 
            {
                val GKString = deviceQueue.poll
                val GKcommand = GKString.toString
                val GKItemName = GKcommand.split("#").get(0)
                logInfo(logName, "GK_ItemName - " + GKItemName)
                val GKItemCommand = GKcommand.split("#").get(1)
                logInfo(logName, "GK_ItemCommand - " + GKItemCommand)

                sendCommand(GKItemName,GKItemCommand)
                logInfo(logName, "deviceQueue - Item - " + GKItemName + " / cmd - " + GKItemCommand + " - SENT")
                timer.reschedule(now.plusMillis(delay))
            }
            else
            {
                timer = null
            }
        ])
    }
end

I now get the error I was getting that started this part of the thread!:

OH.log:

2020-05-04 16:37:43.991 [INFO ] [se.smarthome.model.script.GateKeeper] - GK_ItemName - Spot_GF_LR_6_Color
2020-05-04 16:37:44.000 [INFO ] [se.smarthome.model.script.GateKeeper] - GK_ItemCommand - 100,50,100
2020-05-04 16:37:44.006 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert '100,50,100' to a command type which item 'Spot_GF_LR_6_Color' accepts: [PercentType, OnOffType, IncreaseDecreaseType, RefreshType].
2020-05-04 16:37:44.015 [INFO ] [se.smarthome.model.script.GateKeeper] - deviceQueue - Item - Spot_GF_LR_6_Color / cmd - 100,50,100 - SENT
2020-05-04 16:37:45.527 [INFO ] [se.smarthome.model.script.GateKeeper] - GK_ItemName - Spot_GF_LR_7_Color
2020-05-04 16:37:45.535 [INFO ] [se.smarthome.model.script.GateKeeper] - GK_ItemCommand - 100,50,100
2020-05-04 16:37:45.540 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert '100,50,100' to a command type which item 'Spot_GF_LR_7_Color' accepts: [PercentType, OnOffType, IncreaseDecreaseType, RefreshType].
2020-05-04 16:37:45.548 [INFO ] [se.smarthome.model.script.GateKeeper] - deviceQueue - Item - Spot_GF_LR_7_Color / cmd - 100,50,100 - SENT

events.log

2020-05-04 16:37:39.426 [ome.event.ItemCommandEvent] - Item 'vLightsGatekeeper_Set' received command Spot_GF_LR_6_Color#ON
2020-05-04 16:37:39.434 [vent.ItemStateChangedEvent] - vLightsGatekeeper_Set changed from Spot_GF_LR_7_Color#OFF to Spot_GF_LR_6_Color#ON
2020-05-04 16:37:39.448 [ome.event.ItemCommandEvent] - Item 'vLightsGatekeeper_Set' received command Spot_GF_LR_7_Color#ON
2020-05-04 16:37:39.463 [ome.event.ItemCommandEvent] - Item 'vLightsGatekeeper_Set' received command Spot_GF_LR_6_Color#100,50,100
2020-05-04 16:37:39.472 [vent.ItemStateChangedEvent] - vLightsGatekeeper_Set changed from Spot_GF_LR_6_Color#ON to Spot_GF_LR_7_Color#ON
2020-05-04 16:37:39.487 [ome.event.ItemCommandEvent] - Item 'vLightsGatekeeper_Set' received command Spot_GF_LR_7_Color#100,50,100
2020-05-04 16:37:39.490 [vent.ItemStateChangedEvent] - vLightsGatekeeper_Set changed from Spot_GF_LR_7_Color#ON to Spot_GF_LR_6_Color#100,50,100
2020-05-04 16:37:39.498 [vent.ItemStateChangedEvent] - vLightsGatekeeper_Set changed from Spot_GF_LR_6_Color#100,50,100 to Spot_GF_LR_7_Color#100,50,100
2020-05-04 16:37:40.962 [ome.event.ItemCommandEvent] - Item 'Spot_GF_LR_6_Color' received command ON
2020-05-04 16:37:40.964 [nt.ItemStatePredictedEvent] - Spot_GF_LR_6_Color predicted to become ON
2020-05-04 16:37:40.992 [vent.ItemStateChangedEvent] - Spot_GF_LR_6_Color changed from 0 to 100
2020-05-04 16:37:42.489 [ome.event.ItemCommandEvent] - Item 'Spot_GF_LR_7_Color' received command ON
2020-05-04 16:37:42.495 [nt.ItemStatePredictedEvent] - Spot_GF_LR_7_Color predicted to become ON
2020-05-04 16:37:42.547 [vent.ItemStateChangedEvent] - Spot_GF_LR_7_Color changed from 0 to 100

So, Spot_GF_LR_7_Color is a color channel, it’s passing the 100,50,100 correctly? It just doesn’t accept it as it’s not a HSBType / Percent Type so doesn’t actually send the command???

You’d better check that. It’s an Item, not a channel. It makes no odds what flavour channel you linked it to, it’s the Item you are sending commands to so it is the Item type that counts for what commands are allowed.

openHAB is clear enough.

1 Like

Nailed it…hadn’t even thought of looking at this part…I have the Spot_GF_LR_7_Color item declared as a Dimmer, not a Color…I’ve been pouring over the rules and didn’t even think it could be the item type definition as it has been working for other ON/OFF commands…

Right, off to play…thanks for your help…

EDIT

Working now, how I expected it to work! Lesson learned - never overlook the simple…