How to keep status synchronised between multiple items?

Hi,
I’m trying to solve a rare problem with Xiaomi light, which support HSB colour channel but use another brightness channel for changing brightness (I think it’s perhaps a binding issue). To make it work I want to re-create a proper Color item that can also control the brightness:

Color Xiaomi_gateway_color <rgb> (gXiaomiGatewayLight) {channel="mihome:gateway:xxxxx:xxxxx:color" }
Dimmer Xiaomi_gateway_brightness <dimmablelight> (gXiaomiGatewayLight){channel="mihome:gateway:xxxxx:xxxxx:brightness" }
Color Xiaomi_gateway_color_homekit "Mi Hub Light" 

Ok now I need to make some rules to make sure:

  1. When Xiaomi_gateway_color_homekit changes, it updates Xiaomi_gateway_color as well as Xiaomi_gateway_brightness
  2. When Xiaomi_gateway_color OR Xiaomi_gateway_brightness changes, it updates Xiaomi_gateway_color_homekit

I found it’s almost impossible to make the rules working reliably, below is what I have so far:

rule "Sync status to homekit"
when
  Item Xiaomi_gateway_color changed or
  Item Xiaomi_gateway_brightness changed or
  System started 
then 
  var HSBType colour = Xiaomi_gateway_color.state as HSBType
  var HSBType old = Xiaomi_gateway_color_homekit.state as HSBType
  var HSBType next = new HSBType(new DecimalType(colour.hue.intValue),new PercentType(colour.saturation.intValue),Xiaomi_gateway_brightness.state)
  if(colour.hue.intValue != old.hue.intValue || colour.saturation.intValue != old.saturation.intValue || Xiaomi_gateway_brightness.state!= old.brightness){
    logInfo("Info", "Xiaomi: sync lighting from xiaomi (" +colour+ ") and brightness " + Xiaomi_gateway_brightness.state+ " to homekit (" +old+ ")")
    Xiaomi_gateway_color_homekit.postUpdate(next)
  }
end

rule "Sync status from homekit"
when
  Item Xiaomi_gateway_color_homekit changed 
then 
  var HSBType colour = Xiaomi_gateway_color_homekit.state as HSBType
  var HSBType old = Xiaomi_gateway_color.state as HSBType
  if(colour.hue.intValue != old.hue.intValue || colour.saturation.intValue != old.saturation.intValue || colour.brightness!= Xiaomi_gateway_brightness.state){
    logInfo("Info", "Xiaomi: sync lighting from homekit (" + colour + ") to xiaomi (" +old+ ")")
    var HSBType next = new HSBType(new DecimalType(colour.hue.intValue),new PercentType(colour.saturation.intValue), colour.brightness) 
    Xiaomi_gateway_color.sendCommand(next)
    Xiaomi_gateway_brightness.sendCommand(colour.brightness)
  }
end

Whenever I change Xiaomi_gateway_color_homekit, it sends two commands with inconsistent values, which then triggers the Xiaomi_gateway_color_homekit to flip the state, which then triggers more changes to Xiaomi_gateway_color and Xiaomi_gateway_brightness.

So I’d like to ask if my approach to the solution is reasonable and how to script it so that it doesn’t trigger a cascade chain invoke of rules (with states flip back and force)?

Many thanks in advance!

Just to be clear, sending a simple number as a command to Xiaomi_gateway_color does not work. That’s supposed to work and if it doesn’t you need to file an issue on the MiHome binding.

Again, if this is the same device then the binding should keep these Items in sync for you by default. If it’s not an issue needs to be filed on the binding. This is not something that should be worked around in rules. It is a bug in the binding.

It’s not reasonable in that the binding is supposed to be handling this stuff already. You should not need the Dimmer Channel at all. You can send Dimmer commands to a Color Item and it will process those as Dimmer commands.

And even if there was some reason why that wouldn’t be possible (e.g. in cases where there is a separate Channel to represent the color temperature), the binding is supposed to update all the Items for that device when it processes the command on one of them. This is not something you should (nor do I think you even can) manage in rules.

But there are situations where one does need to keep two Items in sync (e.g. one’s a proxy Item, linked to two different devices like more than one switch to control a single light, etc.). In those cases, you usually need to have a proxy Item and your rules need a test to only update the proxy Item when the change is different from the proxy Item’s current state. Sometimes you can get away with just the two Items.

It looks something like:

rule "Sync Items"
when
    Item ColorItem changed or
    Item DimmerItem changed
then
    var newDimmer = newState.as(PercentType) // this will just give you the dimmer value regardless of which Item changed
    if(ColorItem.getStateAs(PercentType) != newDimmer) ColorItem.sendCommand(newDimmer)
    else if(DimmerItem.state != newDimmer) DimmerItem.sendCommand(newDimmer)
end

It usually works best if all the Items are the same type but at least Color and Dimmer can be made compatible.

But again, as I said, this is not something you should need to do. You just need the one Color Item and if that doesn’t work, file an issue on the binding.

Hi, thanks a lot for the help! I have now create an issue to the binding, hope this can be solved by the binding.