Mirror Device Behavior in Routines Running Locally

Sorry for the delay. I’m asking about this situation internally, I’ll let you know once I have an update.

Hi @nayelyz , any updates ?

2 Likes

@nayelyz I gave you sometime ago access to my smartthings so that support could have a look at my situation but nothing happened since then, can you please see if any update happened ?

Thanks a lot.

1 Like

Hi, @Michaelw
Sorry about that, I just asked the corresponding team again since they haven’t provided more information.

Hi, I’m still not seeing Smart Lighting in routines section of the app. I’m based in Australia and currently need to have multiple routines to just sync/mirror a couple of light switches. Any update on when this is coming to Aus?

1 Like

Hi @nayelyz,

Any updates ?, still nothing on smart Lighting

I have implemented the rules-based solution on multiple dimmer/switch groups in my house.
The intent is that an action taken on one member in a group is reflected on all others.

Initially, I deployed this solution on a SmartThings V2 hub.
Things worked but, ocassionally, I would experience the problems described here

That is, an on/off or dimmer action would cause the switches in the group to forever bounce back and forth between the old and new states.
The lights would forever go on and off, on and off … or they would forever brighten and dim, brighten and dim …

Because of its native Matter over Thread capability and the relatively recent hub replacement support, I “upgraded” to a SmartThings/Aeotec V3 hub.
Things got much worse.
Rather than the problem occasionally happening, it consistently happens.
Consistency is better for finding and correcting the problem, I suppose, but I have yet to do that.

This appears to be some kind of race condition.
My understanding is that the V2 hub is actually a faster machine than the V3 version so that factor might weigh into who and when races are won.

The worst case seems to be when a switch action is quickly followed by another.
This is a typical human interaction for my dimmers that have dim up and down buttons.
So, I gave up on synchronizing the dimmer state.
Still a stutter on the on/off switch can start things looping again.
Ugh!

1 Like

Hi, @rossetyler
Have you seen the behavior in the logs when you change the status of a device? I wonder if the capability events show also a back-and-forth from the communication between the Hub and the device.

I don’t know what you mean by “logs”. The history of the affected devices show that they were going on and off.

./smartthings edge:drivers:logcat # matter switch driver

shows more detail

Sorry, I mean the Hub logs, the devices of your automations are for Hub-Connected devices only or do they include Cloud-connected devices?

In the driver logs, you can see the events generated and where they come from. If it comes from the device’s report or automations.
I mean using the CLI command of smartthings edge:drivers:logcat. If your devices belong to different drivers, you can use the flag --all.

They are all hub-local matter devices.
logcat shows the on-off-on-off … looping

see DM

Thank you for sending the logs, @rossetyler
I need to check this further, but taking a quick look, I see the following behavior:

In those interactions, it seems that after sending an Off command, the device reports its value as “On” which I imagine triggers the other mirror automation, so, the device is responding with a different status which emits a capability event and can cause the loop issue. I’ll see with the engineering team if I’m not getting this wrong or how we can avoid it.

You have to check the state of the mirror device before blindly sending it a command. For example:

Switch B is off (pre-condition state check)
  If Switch A turns on 
     then turn on Switch B

Switch A is off (pre-condition state check)
  If Switch B turns on 
    then turn on Switch B

and, of course, you need two corresponding Routines for the opposite state on each switch.

You can also use the Aplicaciones Virtuales Mc Edge driver from @Mariano_Colmenarejo which has a mirroring function that can be used in Routines.

4 Likes

@h0ckeysk8er
Thanks!

I am writing Rules (applied with the SmartThings CLI), not Routines (applied through the SmartThings app).

Unfortunately, the Rules suggested by @nayelyz

… do not work for me as I get the “forever ping-pong” effect.

I may be wrong but I don’t think I could compose a Routine to synchronize the dimmer state across a group of switches.

Anyway, I added the check you suggested and the behavior, so far, is much better. Rapid button presses do sometimes have confusing results (bounce one or two times) but I am not seeing the forever ping-ponging between states. A logcat of the driver confirms that it is not forever spinning.

This is an example of what works better for me:

{
    "name": "sync.hallway.dimmers",
    "sequence": {"actions": "parallel"},
    "actions": [{
            "if": {
                "changes": {"equals": {"aggregation": "any", "left": {"string": "on"}, "right": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}},
                "then": [{
                    "if": {
                        "not": {
                            "equals": {"aggregation": "any", "left": {"string": "on"}, "right": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}
                        },
                        "then": [{
                            "command": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "commands": [{"component": "main", "capability": "switch", "command": "on", "arguments": []}]}
                        }]
                    }
                }],
                "else": [        {
                    "if": {
                        "changes": {"equals": {"aggregation": "any", "left": {"string": "off"}, "right": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}},
                        "then": [{
                            "if": {
                                "not": {
                                    "equals": {"aggregation": "any", "left": {"string": "off"}, "right": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}
                                },
                                "then": [{
                                    "command": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "commands": [{"component": "main", "capability": "switch", "command": "off", "arguments": []}]}
                                }]
                            }
                        }]
                    }
                }]
            }
        },
        {
            "if": {
                "changes": {
                    "operand": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switchLevel", "attribute" : "level"}}
                },
                "then": [{
                    "if": {
                        "not": {
                            "equals": {"aggregation": "any", "left": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switchLevel", "attribute": "level", "trigger": "Auto"}}, "right": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switchLevel", "attribute": "level", "trigger": "Auto"}}}
                        },
                        "then": [
                            {"command": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "commands": [{"component": "main", "capability": "switchLevel", "command": "setLevel", "arguments": [{"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switchLevel", "attribute" : "level"}}]}]}}
                        ]
                    }
                }]
            }
        },
        {
            "if": {
                "changes": {"equals": {"aggregation": "any", "left": {"string": "on"}, "right": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}},
                "then": [{
                    "if": {
                        "not": {
                            "equals": {"aggregation": "any", "left": {"string": "on"}, "right": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}
                        },
                        "then": [{
                            "command": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "commands": [{"component": "main", "capability": "switch", "command": "on", "arguments": []}]}
                        }]
                    }
                }],
                "else": [        {
                    "if": {
                        "changes": {"equals": {"aggregation": "any", "left": {"string": "off"}, "right": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}},
                        "then": [{
                            "if": {
                                "not": {
                                    "equals": {"aggregation": "any", "left": {"string": "off"}, "right": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switch", "attribute": "switch", "trigger": "Auto"}}}
                                },
                                "then": [{
                                    "command": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "commands": [{"component": "main", "capability": "switch", "command": "off", "arguments": []}]}
                                }]
                            }
                        }]
                    }
                }]
            }
        },
        {
            "if": {
                "changes": {
                    "operand": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switchLevel", "attribute" : "level"}}
                },
                "then": [{
                    "if": {
                        "not": {
                            "equals": {"aggregation": "any", "left": {"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switchLevel", "attribute": "level", "trigger": "Auto"}}, "right": {"device": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "component": "main", "capability": "switchLevel", "attribute": "level", "trigger": "Auto"}}}
                        },
                        "then": [
                            {"command": {"devices": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"], "commands": [{"component": "main", "capability": "switchLevel", "command": "setLevel", "arguments": [{"device": {"devices": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"], "component": "main", "capability": "switchLevel", "attribute" : "level"}}]}]}}
                        ]
                    }
                }]
            }
        }
    ]
}

Hi, @rossetyler
I asked the engineering team about this behavior and they mentioned it would be helpful to have more information to see why they alternate between on/off even if it’s fewer times now.
Can you share the following, please?

  1. New driver logs of when you turn a device on/off and the new Rule is executed
  2. Hub logs after you replicated the issue. To do so, follow this process:
  1. In the Advanced Users app, enter the “Hubs” section
  2. Enter the corresponding Hub and click on “Dump Hub logs”
  3. Confirm the process by clicking on “Dump Hub logs” again in the pop-up.
  4. You’ll get a green box at the top confirming the Hub logs were requested.
  1. The Hub ID you see in the Advanced users app, for example:
    image

Hi, @rossetyler
Following up, the engineering team mentioned they observed the following:

  • The first light hallway:Light2 receives a command to set its lighting level to 68, afterwards, it looks to be manually updated at the light switch to level 51.
  • However, at that time the light hallway:Light1 has already started sending a command to set its light level to 68.
  • Once that command has been sent and a subscription report verifying the light level is received, an event is emitted for that device, triggering the routine and then attempting to set hallway:Light2 back to 68 to sync with the other device.

So, this is an issue of race conditions, and would only work properly if changes to the lights were made only until both devices are synced and on the same page.

They mentioned that lighting groups help to have devices synchronized. Have you checked if they behave differently than the routine?

1 Like

The log events I DM’ed to you were all triggered solely from natural human interaction with the dimmer up (or was it dimmer down?) button on the hallway:Light2 switch. Press, press, press for up, up, up. A similar thing happens with a less natural repeated interaction with the on/off switch.

These are simple light switches at opposite ends of a hallway that control a common set of lights. hallway:Light actually carries the light load and hallway:Light2 is just a secondary interface. Everyone knows how to use such light switches. A solution that requires operator training is, IMO, not acceptable.

A solution for synchronizing the state of a set of switches like this should be natively supported by SmartThings. Unfortunately, your offered work-around does not work. While my modified solution works better (I am not sure why) its behavior will still confuse anyone that has ever used a light switch before (everyone).

Yes, I think so. It is interesting that the “race” outcomes were different (better!) on my older (faster?) V2 hub than my newer (slower?) V3 hub.

Please tell, how would a SmartThings lighting group help?

Perhaps this problem reveals why SmartThings does not offer a native solution. I expected to find such a solution in Smart Lighting. Perhaps SmartThings has no capability for guards to avoid such race conditions. Perhaps this capability should be added.

I think it is enlightening to go back to the behavior of your solution that results in ping-ponging back and forth between states forever. Perhaps if there were some support to guard against the evident infinite rule re-entry then a solution could be found.

2 Likes

I did want to just note that this type of race condition occurs differently with different brands/models of switches.

Many of the more expensive switches have “debounce” which, among other things, slightly delays the transmission of the event. That in turn can give the hub time to get new states recorded.

We have even seen situations where the same model of tuya-made Zigbee switch had different behaviors when re-branded and sold by different manufacturers, because the firmware was just slightly different. (Tuya switches are particularly vulnerable to race conditions.)

Industrywide, usually the most reliable solution is when it’s built into the firmware of a switch itself. For example, Z wave Direct Association will synchronize a master and auxiliary switch beautifully without needing to do anything with automations at all. You can also do it with zigbee binding and groupcasting, although that’s not supported by smartthings. And some matter switches are providing this with their own linked auxiliaries.

So I am not by any means saying that smartthings shouldn’t provide more ways to synchronize multiple switches, including switches of different protocols. I definitely think they should.

But I did just want to mention that sometimes there are other ways to solve this issue if it becomes a high priority for a specific location. :man_shrugging:t2:

4 Likes

@nayelyz
What is the status of this issue?
Is it an acknowledged problem?
Is it being worked on?
ETA?

Again, it seems that there is a race condition here that causes my rules to be re-entered forever.
Software race conditions can be solved if there are tools to do so.
Unfortunately, I can find none at my disposal.
Please advise.

Please support switch/dimmer mirroring natively.

Hi, @rossetyler

Sorry for the delay.
I asked the engineering team about this, I’ll let you know once I get more info.

1 Like