Bulb color sync ChatGPT JSON Rule

It is certainly interesting.

Comparing device attributes to themselves is an intriguing way of making the rules trigger on new data. It kind of looks like it might actually work. It certainly makes more sense than using changes on an operand which is the way I’ve seen it suggested it can be done, despite that being completely at odds with the documentation.

Using the device attribute value in a command argument as it does can apparently be done so that might work.

The one I’ve not seen before is using the on or off attribute value of the switch as the command. I like that a lot. I hope it works.

Apart from having a bit lopped off the end, it actually looks like a rather elegant solution to the problem if you can actually do those things in practice.

3 Likes

Sometimes I make posts that are irrelevant.

Hi, @RJGill84

The colorControl capability is tricky, so, I created a sample, I just tested it and it worked on virtual devices that include it:

{
    "name": "Changes - colorControl",
    "actions": [
      {
        "if": {
          "changes": {
            "operand": {
              "device": {
                "devices": [
                  "device1-id"
                ],
                "component": "main",
                "capability": "colorControl",
                "attribute": "saturation"
              }
            }
          },
          "then": [
            {
              "command": {
                "devices": [
                  "device2-id"
                ],
                "commands": [
                  {
                    "component": "main",
                    "capability": "colorControl",
                    "command": "setColor",
                    "arguments": [
                      {
                        "map":{
                            "hue": {
                              "device": {
                                "devices": [
                                  "device1-id"
                                ],
                                "component": "main",
                                "capability": "colorControl",
                                "attribute": "hue"
                              }
                            },
                            "saturation": {
                              "device": {
                                "devices": [
                                  "device1-id"
                                ],
                                "component": "main",
                                "capability": "colorControl",
                                "attribute": "saturation"
                              }
                            }
                        }
                      }
                    ]
                  }
                ]
              }
            }
          ]
        }
      }
    ]
  }

Note: Currently, the widget in the app that allows us to select a color uses the command “setColor” and it gets the values of “hue” and “saturation” as the arguments, therefore, we need to save them in the corresponding attributes, that’s why this Rule is based in the change of one of them.
The attribute “color” is no longer used in the app to define a color.

1 Like

I can accept that this construct works but please can the documentation be sorted out to explain why. The API Reference clearly states that changes is ‘A condition that returns true when its evaluation resolves to true and the previous evaluation resolved to false.’ How does the operand evaluate to either true or false?

In the documentation of Rules, there’s another description:

" changes is a Condition that tracks the state of the operation it contains, returning true when the state of the inner operation transitions from false to true."

This gives the understanding that when the current state of the device is not the expected one according to what we set in the “operation” inside “changes”, then, it remains false. Otherwise, when an event is received and it matches the content of the “operation”, it will become true.
In the case of “operand”, we’re checking if the device got something on that specific capability and attribute, it can be any value. That’s why it is useful in this case because other conditions need a specific value to compare with the new event.

I’ll check with the team if they can provide more info about it, what I shared above is my understanding of how it works based on my tests.

This is interesting because it would allow doing device behavior sync’ing by just determining if there had been a change to some capability of the device. And unfortunately, it’s not exposed in the Routines for things like dim level where it would be nice to know that it had simply changed and not changed to some specific value, range, etc. like what is implemented currently.

1 Like

Despite both using the same back end (Rules engine), there must be something that allows the interpretation between what the user selects and what it means in the Rules API language, in the case of the options you mention, adding them to the Routines tool would be a feature request. I created one for mirror behavior a while back, but I haven’t got any response, I’ll include your comment there.

2 Likes

I know I’ve been badgering you for years about this issue, but I think at last I see what is going on. The confusion is not caused by changes but by operand.

There is absolutely no description of operand in the Documentation or the API Reference. All we are told is that it contains an ‘Operand’ object.

If operand is an ‘Operand’ that returns true if the current event is relevant to its content then the failure to document it as such is right up there with the biggest failures that SmartThings has ever had. It is of absolutely colossal importance to the understanding and creation of Rules.

One of the strengths of webCoRE pistons is that they could target their response specifically to the event that caused the piston to run. Now it turns out that similar functionality has been hiding in plain sight in Rules for ages.

It rather sounds like it is in fact possible to know when a Rule was activated by a specific button being pressed. That in itself is game changing.

I am now kicking myself for not realising what was going on.

4 Likes

I fully appreciate that there has to be something that translates the UI representation into the backend rules. What is disappointing is that the ability to trigger on dim level is a recently added feature and one would think that they would have taken into account all the triggering cases in the Rules and built those into the UI. They clearly thought of equals, greater than, less than, and in a range. Seems like it would have been easy to have also added a simple “Changes” to the list.

Thank you for the code sample @nayelyz

I provided your reply to ChatGPT and it rewrote the code based on your suggestions. I find its responses just as interesting as the code.



{
  "name": "Sync Hue, Saturation, Brightness, and On/Off",
  "actions": [
    {
      "if": {
        "changes": {
          "operand": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "colorControl",
              "attribute": "saturation"
            }
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "commands": [
                {
                  "component": "main",
                  "capability": "colorControl",
                  "command": "setColor",
                  "arguments": [
                    {
                      "map": {
                        "hue": {
                          "device": {
                            "devices": [
                              "master-bulb-id"
                            ],
                            "component": "main",
                            "capability": "colorControl",
                            "attribute": "hue"
                          }
                        },
                        "saturation": {
                          "device": {
                            "devices": [
                              "master-bulb-id"
                            ],
                            "component": "main",
                            "capability": "colorControl",
                            "attribute": "saturation"
                          }
                        }
                      }
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    {
      "if": {
        "changes": {
          "operand": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "switchLevel",
              "attribute": "level"
            }
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "component": "main",
              "capability": "switchLevel",
              "command": "setLevel",
              "arguments": [
                {
                  "device": {
                    "devices": [
                      "master-bulb-id"
                    ],
                    "component": "main",
                    "capability": "switchLevel",
                    "attribute": "level"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "if": {
        "changes": {
          "operand": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "switch",
              "attribute": "switch"
            }
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "component": "main",
              "capability": "switch",
              "command": {
                "device": {
                  "devices": [
                    "master-bulb-id"
                  ],
                  "component": "main",
                  "capability": "switch",
                  "attribute": "switch"
                }
              }
            }
          }
        ]
      }
    }
  ]
}

What are your thoughts on this version @orangebucket?

Less interesting than the first one but probably a better bet. What I remain suspicious of is this bit:

        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "component": "main",
              "capability": "switch",
              "command": {
                "device": {
                  "devices": [
                    "master-bulb-id"
                  ],
                  "component": "main",
                  "capability": "switch",
                  "attribute": "switch"
                }
              }
            }
          }
        ]
      }

What it is trying to do is use the current attribute value of the master device, i.e. on or off, as the name of the command to issue to the devices being synced, again on or off. If it works it is a thing of beauty, but although it may work for the values of arguments, I have never seen it used like this and I couldn’t get it to be accepted when I tried it.

I should add that my not having seen it done before really isn’t remarkable. As with many things SmartThings, my theoretical knowledge far exceeds my practical requirements.

3 Likes

@orangebucket ChatGPT provided me with this updated code for on/off based on your feedback:


{
  "name": "Sync Hue, Saturation, Brightness, and On/Off",
  "actions": [
    // ... (hue, saturation, and brightness syncing actions)
    {
      "if": {
        "changes": {
          "operand": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "switch",
              "attribute": "switch"
            }
          }
        },
        "equals": "on",
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "component": "main",
              "capability": "switch",
              "command": "on"
            }
          }
        ]
      }
    },
    {
      "if": {
        "changes": {
          "operand": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "switch",
              "attribute": "switch"
            }
          }
        },
        "equals": "off",
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "component": "main",
              "capability": "switch",
              "command": "off"
            }
          }
        ]
      }
    }
  ]
}

I think it is getting a bit colder now as changes is a boolean and equals doesn’t work anything like that. The way it is normally done would be something like …

  "then": [
    {
      "if": {
        "equals": {
          "left": {
            "device": {
              "devices": [
                "master-bulb-id"
              ],
              "component": "main",
              "capability": "switch",
              "attribute": "switch"
            }
          },
          "right": {
            "string": "off"
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "commands": [
                {
                  "component": "main",
                  "capability": "switch",
                  "command": "on"
                }
              ]
            }
          }
        ],
        "else": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "commands": [
                {
                  "component": "main",
                  "capability": "switch",
                  "command": "off"
                }
              ]
            }
          }
        ]
      }
    }
  ]
1 Like

Thanks for going back & forth with me on this. It suggested this in response to your post:

{
  "name": "Sync color, brightness, and on/off from master bulb",
  "actions": [
    {
      "if": {
        "changes": {
          "device": {
            "devices": [
              "master-bulb-id"
            ],
            "component": "main",
            "capability": "switch",
            "attribute": "switch"
          }
        },
        "then": [
          {
            "if": {
              "equals": {
                "left": {
                  "device": {
                    "devices": [
                      "master-bulb-id"
                    ],
                    "component": "main",
                    "capability": "switch",
                    "attribute": "switch"
                  }
                },
                "right": {
                  "string": "on"
                }
              },
              "then": [
                {
                  "command": {
                    "devices": [
                      "bulb-1-id",
                      "bulb-2-id",
                      "bulb-3-id"
                    ],
                    "commands": [
                      {
                        "component": "main",
                        "capability": "switch",
                        "command": "on"
                      }
                    ]
                  }
                }
              ],
              "else": [
                {
                  "command": {
                    "devices": [
                      "bulb-1-id",
                      "bulb-2-id",
                      "bulb-3-id"
                    ],
                    "commands": [
                      {
                        "component": "main",
                        "capability": "switch",
                        "command": "off"
                      }
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "if": {
        "changes": {
          "device": {
            "devices": [
              "master-bulb-id"
            ],
            "component": "main",
            "capability": "colorControl",
            "attribute": "hue"
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
              "commands": [
                {
                  "component": "main",
                  "capability": "colorControl",
                  "command": "setColor",
                  "arguments": [
                    {
                      "map": {
                        "hue": {
                          "device": {
                            "devices": [
                              "master-bulb-id"
                            ],
                            "component": "main",
                            "capability": "colorControl",
                            "attribute": "hue"
                          }
                        },
                        "saturation": {
                          "device": {
                            "devices": [
                              "master-bulb-id"
                            ],
                            "component": "main",
                            "capability": "colorControl",
                            "attribute": "saturation"
                          }
                        }
                      }
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    {
      "if": {
        "changes": {
          "device": {
            "devices": [
              "master-bulb-id"
            ],
            "component": "main",
            "capability": "switchLevel",
            "attribute": "level"
          }
        },
        "then": [
          {
            "command": {
              "devices": [
                "bulb-1-id",
                "bulb-2-id",
                "bulb-3-id"
              ],
          "commands": [
            {
              "component": "main",
              "capability": "switchLevel",
              "command": "setLevel",
              "arguments": [
                {
                  "device": {
                    "devices": [
                      "master-bulb-id"
                    ],
                    "component": "main",
                    "capability": "switchLevel",
                    "attribute": "level"
                  }
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Are we getting warmer or is it just veering off course now? :joy:

EDIT: Sorry, posted the wrong one initially.

I am not seeing anything that I’d do any differently if I was writing it. If it doesn’t work it is certainly a good attempt.

Sadly there seems to have been syntax errors of some kind as the Rules API was complaining about the device field being unrecognized. After several revisions, I went back to the drawing board and started a new chat - and was presented with this code. It works perfectly and syncs the bulb colors - but it does NOT sync the brightness level or on/off.

Thats OK really because I can do that with SmartLighting. PROBLEM SOLVED! The moral of the story here is: customers shouldn’t have to resort to artificial intelligence to hack together a solution to something simple like color coordination, that is available in every platform other than SmartThings.

{
  "if": {
    "changes": {
      "operand": {
        "device": {
          "devices": [
            "Master-Bulb"
          ],
          "component": "main",
          "capability": "colorControl",
          "attribute": "saturation"
        }
      }
    },
    "then": [
      {
        "command": {
          "devices": [
            "Slave-Bulb-1",
            "Slave-Bulb-2",
            "Slave-Bulb-3",
            "Slave-Bulb-4",
            "Slave-Bulb-5"
          ],
          "commands": [
            {
              "component": "main",
              "capability": "colorControl",
              "command": "setColor",
              "arguments": [
                {
                  "map": {
                    "saturation": {
                      "device": {
                        "devices": [
                          "Master-Bulb"
                        ],
                        "component": "main",
                        "capability": "colorControl",
                        "attribute": "saturation"
                      }
                    },
                    "level": {
                      "device": {
                        "devices": [
                          "Master-Bulb"
                        ],
                        "component": "main",
                        "capability": "switchLevel",
                        "attribute": "level"
                      }
                    },
                    "hue": {
                      "device": {
                        "devices": [
                          "Master-Bulb"
                        ],
                        "component": "main",
                        "capability": "colorControl",
                        "attribute": "hue"
                      }
                    },
                    "switch": {
                      "device": {
                        "devices": [
                          "Master-Bulb"
                        ],
                        "component": "main",
                        "capability": "switch",
                        "attribute": "switch"
                      }
                    }
                  }
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Just curious: what’s the state of smartthings lighting groups these days?

Can you include them in Scenes?

Are they actionable with a rules API?

If so, that might offer some other alternatives. I know the functionality on these has been changing, I just haven’t kept up with it. :thinking:

1 Like

That’s a great question. I abandoned lighting groups when I determined they also don’t support color syncing. I’m sure they’re useful for other things. But I’ve been desperately trying to get 6 bulbs sync’d in my home theater since the demise of Color Coordinator (it stopped working before the Edge transition). First world problems, but manually adjusting 6 bulbs when you want the entire room one color is annoying and cumbersome.

To my knowledge color syncing is impossible, except with Sharptools or @Mariano_Colmenarejo’s latest driver for Zigbee bulbs. Since these are Lifx, and I need them to be sync’d with a virtual bulb, that option doesn’t work.

I’m so relieved I have this working after about 2 years :joy:

1 Like

I’ve only lightly toyed with virtual colour lights so I have to defer to those with real experience.

However, as far as I can see lighting groups work for colour light syncing and you can use them in the Rules API like any other device.

Unfortunately they do not present with the colour support in the mobile apps and that screws over Scenes because Scenes are managed like Routines as a private plaything of the app, despite also being accessible to the public API.

Lighting Groups are a type of Device Group, and they present as a single device of type GROUP. However the API doesn’t include them in the list of devices in your Location so you need to hunt them down in the API in the /devicegroups endpoint which is where the group specific stuff is handled. The deviceGroupId is the same as the deviceId. You can see the device in the API, it is just the listing that filters it out.

As ever, this stuff might be ‘hidden’ for a reason.

1 Like

Have been following this thread with interest, especially as I am trying to get into rules, as a non-programmer, using templates.
Fascinating to see the ability of ChatGPT, and I couldn´t resist copying the code and trying to create a rule, but no way, always a format error (except for the code by @nayelyz which runs perfectly -THANK YOU!)
Now sync has been covered in color and saturation, but I precisely am interested in brightness or “switchLevel”, and don´t want to use Smart Lighting or groups.
Trying to read through to understand this, but what is the final conclusion on this point - can maybe someone can confirm - that level can be synchronised by this changes/operand/attribute route or is this barking up the wrong tree?
Can it be done?
Many thanks if someone can give us a hand

1 Like