Mirror behavior in routines running local

@nayelyz

How is everything? Is there anything in progress on the part of the ST team to release the feature of mirroring behavior that is currently available in the smartapp smart lighting and putting them also in the routines running locally?

5 Likes

Hi, there!

I’m discussing this with the engineering team to get a better insight as they are different integrations. As soon as I get their feedback, I’ll share it with you.

3 Likes

excellent! because for those who use virtual parallel the option of mirroring behavior is extremely important and as edge switches with more than one channel cannot rename them, it is impossible to use smart lighting for that… so if you migrate this feature to automations and running spot would be a genius move. Thanks!

The engineering team mentioned the mirror functions can be achieved using the Rules API and the changes condition.
It is different depending on the capability configuration to set the attribute value.

For example, the Switch capability has two enum commands that don’t receive any arguments.
In this case, we need to check the change to a specific value (“on”/“off”) and send the same value to the other device.
This sample shows how we can mirror the switch events of a multi-component device that has a switch in two components (light and main), that’s also why only one deviceID is used.

{
    "name":"Mirror switch events of main and light components",
    "actions":[
       {
          "if":{
             "changes":{
                "equals":{
                   "left":{
                      "device":{
                         "devices":[
                            "deviceID"
                         ],
                         "component":"main",
                         "capability":"switch",
                         "attribute":"switch"
                      }
                   },
                   "right":{
                      "string":"on"
                   }
                }
             },
             "then":[
                {
                   "command":{
                      "devices":[
                         "deviceID"
                      ],
                      "commands":[
                         {
                            "component":"light",
                            "capability":"switch",
                            "command":"on"
                         }
                      ]
                   }
                }
             ],
             "else":[
                {
                   "if":{
                      "changes":{
                         "equals":{
                            "left":{
                               "device":{
                                  "devices":[
                                     "deviceID"
                                  ],
                                  "component":"main",
                                  "capability":"switch",
                                  "attribute":"switch"
                               }
                            },
                            "right":{
                               "string":"off"
                            }
                         }
                      },
                      "then":[
                         {
                            "command":{
                               "devices":[
                                  "deviceID"
                               ],
                               "commands":[
                                  {
                                     "component":"light",
                                     "capability":"switch",
                                     "command":"off"
                                  }
                               ]
                            }
                         }
                      ]
                   }
                }
             ]
          }
       },
       {
          "if":{
             "changes":{
                "equals":{
                   "left":{
                      "device":{
                         "devices":[
                            "deviceID"
                         ],
                         "component":"light",
                         "capability":"switch",
                         "attribute":"switch"
                      }
                   },
                   "right":{
                      "string":"on"
                   }
                }
             },
             "then":[
                {
                   "command":{
                      "devices":[
                         "deviceID"
                      ],
                      "commands":[
                         {
                            "component":"main",
                            "capability":"switch",
                            "command":"on"
                         }
                      ]
                   }
                }
             ],
             "else":[
                {
                   "if":{
                      "changes":{
                         "equals":{
                            "left":{
                               "device":{
                                  "devices":[
                                     "deviceID"
                                  ],
                                  "component":"light",
                                  "capability":"switch",
                                  "attribute":"switch"
                               }
                            },
                            "right":{
                               "string":"off"
                            }
                         }
                      },
                      "then":[
                         {
                            "command":{
                               "devices":[
                                  "7eac1137-b397-4b22-ad63-24b67ee58fd6"
                               ],
                               "commands":[
                                  {
                                     "component":"main",
                                     "capability":"switch",
                                     "command":"off"
                                  }
                               ]
                            }
                         }
                      ]
                   }
                }
             ]
          }
       }
    ]
 }

For capabilities that use a setter like switchLevel it’s easier, we just send the current attribute value in the command arguments.
In this sample, we mirror the events of dimmer 1 and dimmer 2 and it’s not necessary using specific values.

{
   "name":"Mirror dimmer 1 and dimmer 2 events of SwitchLevel",
   "actions":[
      {
         "if":{
            "changes":{
               "operand":{
                  "device":{
                     "devices":[
                        "deviceID-dimmer1"
                     ],
                     "component":"main",
                     "capability":"switchLevel",
                     "attribute":"level"
                  }
               }
            },
            "then":[
               {
                  "command":{
                     "devices":[
                        "deviceID-dimmer2"
                     ],
                     "commands":[
                        {
                           "component":"main",
                           "capability":"switchLevel",
                           "command":"setLevel",
                           "arguments":[
                              {
                                 "device":{
                                    "devices":[
                                       "deviceID-dimmer1"
                                    ],
                                    "component":"main",
                                    "capability":"switchLevel",
                                    "attribute":"level"
                                 }
                              }
                           ]
                        }
                     ]
                  }
               }
            ]
         }
      },
      {
         "if":{
            "changes":{
               "operand":{
                  "device":{
                     "devices":[
                        "deviceID-dimmer2"
                     ],
                     "component":"main",
                     "capability":"switchLevel",
                     "attribute":"level"
                  }
               }
            },
            "then":[
               {
                  "command":{
                     "devices":[
                        "deviceID-dimmer1"
                     ],
                     "commands":[
                        {
                           "component":"main",
                           "capability":"switchLevel",
                           "command":"setLevel",
                           "arguments":[
                              {
                                 "device":{
                                    "devices":[
                                       "deviceID-dimmer2"
                                    ],
                                    "component":"main",
                                    "capability":"switchLevel",
                                    "attribute":"level"
                                 }
                              }
                           ]
                        }
                     ]
                  }
               }
            ]
         }
      }
   ]
}

I will create the feature request to have this in the mobile app Routines, but in the meantime, you can use this workaround.
Let me know if you have any questions.

6 Likes

very good to know that we will have this soon in the app’s routines. For now I need to create 4 routines to mirror the behavior of 2 different devices, one of which is if connecting device 1 connects device 2; another to disconnect device 1 disconnect device 2: another to connect device 2 connect device 1 and finally disconnect device 2 disconnect device 1. Very laborious to do and this being the only alternative because as we can’t rename gangs in smartapp a huge list of switch1, switxh2, etc. appears. I will be looking forward to the update.

I cannot assure you this will be available soon, it depends on the prioritization and current workload of our team, as they are all, constantly working to build more cool features for you, please remember also, that you caught us in the middle of the holidays.

If you have any questions using the Rules API for the workaround I can help you out.

I never messed with the rules api. I would rather understand and know how I can make this work using it.

1 Like

Thanks for posting that Nayely. I’m not particularly interested in mirroring but it hadn’t occurred to me that attributes could be used in arguments like that (that said, getting the right format for arguments has always been guesswork). I’d also been wondering what operand was for. It is obvious now I see it used with changes, not that I’ve found a need for that yet.

1 Like

Any update on the mirroring feature being added to routines? I tried to get this set up based on @nayelyz 's code but I think creating a rule from code is too complicated for me.

3 Likes

@nayelyz, I was just looking at this again. While your example makes perfect sense, the API documentation describes the changes operation as …

A condition that returns true when its evaluation resolves to true and the previous evaluation resolved to false.

The main developer documentation says something similar.

Operand is not explained in the API reference. It just appears to be a container. It isn’t clear how that can be true or false for a non-boolean attribute. So I don’t see how the documentation can be correct if your example works.

There is also a terminology issue (as ever).

  • In the API reference if is an action and changes is a condition.
  • However in the main developer documentation if, every, sleep and commands are the conditions and changes, equals etc are operations.

I see what you mean, this needs more elaboration on the functionality so we know what to expect.

  1. I think in the API doc, we need to change the text in parenthesis because despite IF being inside the actions array (which is the task completed by the Rule), it is a condition.
  2. Again, the value in parenthesis is the one that creates this confusion so, instead of reading (BetweenCondition), it should be (BetweenOperation). Also in some descriptions, the word condition is used again, that would change as well.

Did I get that right or what other changes would you propose?

I think that was probably right.

I don’t really care what stuff is called, I would just like consistency in terminology. Unfortunately SmartThings has always been hopeless in that regard (using ‘state’ instead of ‘attribute’ being an ongoing issue).

1 Like

@nayelyz any update on when mirror device will be an option in routines?

2 Likes

Hi, @daviper.

Not so far, the feature requests can take some time to be processed and developed. I already reached out to the team to get more feedback

Just wanted to very belatedly revisit this and say the developers of the Core SDK would appear to fall into the ‘if is an action’ camp in this regard. I guess they read the API.