JSON Consistency - Rules vs Automations

@nayelyz

I find it frustrating that the JSON syntax for rules is different than the syntax for Automations. Yes, most probably these are implemented using different backends but one would think that SmartThings would adopt a universal syntax for all its tools?

And again, the question is “what does the future hold?”

Rules replace automations or …???

3 Likes

What do you mean by “automations” in this case, those created with the Routines tool in the app?
And which syntax are you referring to, can you provide an example, please?

Ok, here’s the JSON that you would create for a rule:

{
  "if": {
    "changes": {
      "equals": {
        "left": {
          "device": {
            "devices": [
              "17ec5cb1-25a0-4923-8fa7-f5b6c95521d6"
            ],
            "component": "main",
            "capability": "switch",
            "attribute": "switch"
          }
        },
        "right": {
          "array": {
            "operands": [
              {
                "string": "on"
              },
              {
                "string": "off"
              }
            ]
          }
        }
      }
    },
    "then": [
      {
        "scene": {
          "scenes": [
            "d733090e-2ff5-4212-8472-fbc9b3ed0c63"
          ]
        }
      },
      {
        "command": {
          "devices": [
            "8c350809-d794-4e44-abcc-102d253e8bc9"
          ],
          "commands": [
            {
              "component": "main",
              "capability": "switch",
              "command": "on"
            }
          ]
        }
      }
    ]
  }
}

and now roughly the same behavior if you create a Routine from the SmartThings IOS app. Note that I recovered the JSON from the SmartThings API Browser as this seems to not be possible from the CLI directly.

{
  "if": {
    "or": [
      {
        "equals": {
          "left": {
            "device": {
              "devices": [
                "17ec5cb1-25a0-4923-8fa7-f5b6c95521d6"
              ],
              "component": "main",
              "capability": "switch",
              "attribute": "switch",
              "trigger": "Always"
            },
            "type": "device"
          },
          "right": {
            "string": "on",
            "type": "string"
          },
          "aggregation": "Any",
          "changesOnly": false
        },
        "type": "equals"
      },
      {
        "equals": {
          "left": {
            "device": {
              "devices": [
                "17ec5cb1-25a0-4923-8fa7-f5b6c95521d6"
              ],
              "component": "switch2",
              "capability": "switch",
              "attribute": "switch",
              "trigger": "Always"
            },
            "type": "device"
          },
          "right": {
            "string": "off",
            "type": "string"
          },
          "aggregation": "Any",
          "changesOnly": false
        },
        "type": "equals"
      }
    ],
    "type": "or",
    "then": [
      {
        "scene": {
          "scenes": [
            "d733090e-2ff5-4212-8472-fbc9b3ed0c63"
          ],
          "sequence": {
            "scenes": "Parallel"
          }
        },
        "type": "scene"
      },
      {
        "command": {
          "devices": [
            "17ec5cb1-25a0-4923-8fa7-f5b6c95521d6"
          ],
          "commands": [
            {
              "component": "main",
              "capability": "switch",
              "command": "off"
            }
          ],
          "sequence": {
            "commands": "Serial",
            "devices": "Serial"
          }
        },
        "type": "command"
      }
    ],
    "sequence": {
      "then": "Parallel",
      "else": "Serial"
    }
  },
  "type": "if"
}

Note that even if you insert the “name” and “actions” wrapper, then basic constructs are different. Example, the requirement for “type” which is not recognized in Rules and many more inconsistencies.

Hope this helps getting my point across.

1 Like

Ok, I checked both JSONs and first, they are two ways of setting a similar functionality which can be seen a lot in Rules. About the “type” property, I’ll see if I can get more info.
About other inconsistencies, I’m guessing you mean the other properties added by default like aggregation, sequence, etc.
You can use them in the Rules but they can have a better use when you have multiple elements to execute or compare.
For example, “sequence” helps you to define if they trigger in serial or parallel order. In a Rule we create directly through the API, the default value is “serial”. It can be used in different sections as shown at the bottom:

"sequence": {
   "then": "Parallel",
   "else": "Serial"
}

“aggregation” allows you to simplify and and or conditions, for example, if you put several device IDs in the array for the equals condition you can use “Any”(Or), or “All” (and) instead of using "or": [] and include each ID separately.

There was a request to add this description in the docs, I’ll follow up on that.

1 Like

Hi. And what is the significance of the “strategy” property found in routines?

I’m guessing that it is there so that each object is clearly identified to help the app reconstruct the Routine from the Rule. Some keys appear in more than one place, for example command is both an action in itself and a key in a device action.

Does it appear anywhere but in sleep? In sleep the values seem to be interrupt or ignore, although mine all say interrupt. Sounds a bit like a flag to determine what to do when a timer is already running.

That’s the only place I’ve seen it, but I didn’t understand its significance and cut it out for my rule. Now I know a bit more, but still don’t really get why the routine inserts it, but it’s not needed for the rule. What would be a use case for this, a practical example so to speak? Sorry if that’s a difficult question - ignore it if you like.

It used to be the case that when, for example, you had a Routine that turned a switch off ten minutes after the triggering event that switch was going to be turned off after ten minutes whether you still wanted it to be or not. However my understanding is that now if the Routine runs the action again the original timer is replaced by a new ten minute timer, which seems to be what users expected. So I am wondering if it is the strategy, which doesn’t get a mention in the API reference, that controls this. This is pure speculation as I haven’t tested it using Rules directly. I am hoping someone else will do that. There might be a more obvious alternate explanation for why things apparently changed.

I am trying to think of practical examples while being only too aware that I could be hopelessly wrong in my speculation in the first place. The only place I use sleep myself is inside a five minute timer so the situation never arises where a sleep is already happening.

I do have Rules to turn off fans when they have been on for a certain period of time. However because they can be turned on in different ways I have to use the change to the on state to trigger the Rule. I do this using a remains condition and an immediate action, but potentially I could do this with an immediate condition and a delayed action if I knew the sleep would be reset when required. At the moment I don’t know how to do this unless the default behaviour of sleep has changed, but perhaps strategy is the key. It would be nice to know.

There will certainly be cases where you don’t want the timer to be messed with but the trouble is the ones I can think of would be rather contrived. For example if a room should always be empty and intrusion is detected, you’d want the delayed response to be unstoppable. You wouldn’t want a second intrusion detection to delay the response.

1 Like

This is an almost frivolous request, but could you request they do something about this …

Clipboard01

It has been like it for months and it makes my eyeballs itch.

And if those responsible for this forum could kindly put an indent before ‘All Categories’ in this, that would be much appreciated. That’s a complete digression though.

Clipboard01

Thats a good explanation, and one I wasn´t able to see, so actually in that way, as I get it, it could be useful for a rule in those situations.
But if I try to use to create a rule in the API Browser it won´t accept, giving an error 422 “target”:“strategy”. Why in rutines but not in rules?
@nayelyz

I really don’t know. Since Routines were first switched to Rules they always seem to have been using a later version. Some changes have trickled through but only some. I’m mainly waiting on notifications so I can eliminate my Routines. The rest of the stuff would be nice to have but whether I’d ever use it is debatable now as the damage has been done. I’ve been waiting too long.

This, and the follow on discussions, are helpful but doesn’t address the crux of my original query: “Why is the JSON syntax for Rules and Routines different?” and as important, "Why are all of the Rules constructs “sequence, aggregations, etc” not currently documented.

If Rules can be more powerful and more pervasive, then it needs to migrate from “creative spelunking” to a formal, complete, supported, documented “language”. @nayelyz, I totally appreciate your help here but having to plow through message threads to get new keywords and usage hints is not the best way forward. Here are my suggestions to your development team:

  1. Document the JSON syntax as a formal BNF grammar. See Lua BNF Grammar. Here’s an example of how LUA is defined as a grammar but I could find countless examples for JSON syntax for SQL, etc that have also been defined as such. I expect that your development team must have some parser that uses something close to this to process a JSON object. Formally documenting this would expose keywords and usage in a comprehensive manner.

  2. Improve your documentation so that all keywords are defined. Example: “Operands” are discussed as a general concept but its usage as a keyword is not documented.

In short, if Rules is a key part of the future of SmartThings, then it must be formally supported in all aspects.

Thanks to the community’s help in getting me through a few hurdles but the impediments to scaling for me and others is a fully supported language as it seems that Rules/JSON is a strategic decision much like the transition to LUA was.

1 Like

I have answered some of my own questions.

  1. JSON Syntax. Documentation is available here. It would be good to enhance the documentation or, at least, put a pointer to this within the main body.

  2. Also, the main Welcome to SmartThings page, has a dead link when trying to hyperlink to the Rules API.

So better than I thought, but still lacking.

The team is already aware of this, however, due to the source of this info, it has been quite hard for them to correct this part without having other issues. They’re still working on it, no ETA yet.

Ok, where are you seeing that? I was thinking of the main page but I see a space there:

@harobinson, I reported the issue with the link you mentioned.

Thanks, I’ll share this with the corresponding team.

Sorry, I don’t have info about that, but I’ll ask the engineering team about that property.

I get it on https://community.smartthings.com/ and when I select any of the menu items, except for ‘Categories’ in the light theme.

‘Categories’ in the light theme doesn’t show ‘All Categories’ at all. In the dark theme it shows it hard up to the edge as all other menus do.

I guess it might be a screen/window width thing as my laptop is pretty modest (1366x768).

Yes, if I reduce the size of the window, it happens at some point. I’ll check if there’s something we can do about it.

Any followup on this?

Yes, sorry for the delay.

The team mentioned the API of o client.smartthings.com/rules is a superset of api.smartthings.com.
Fields like type are required because the “client” API is consumed by the ST App and it was designed based on the corresponding team’s requirements for it. This is how it can be visualized in the app correctly in the Routines tool.

The discrepancies that we can observe are due to the following:

  1. api.smartthings.com is an officially documented API and anything we put in there we need to support it for a wide array of clients/sources. As they are independent of ST, we cannot control how things work on their side, that’s why not all features are available there, especially those that could be invasive like sending push notifications.
  2. The opposite happens for the “client” API which we know is consumed by specific sources owned by ST.
  3. client.smartthings.com is not an officially supported API and it really shouldn’t be used by third-parties.

While this is a valid explanation, it seems to point to two groups that can’t adopt a consistent syntax.

Doesn’t SmartThings expect that folks would take the JSON created by Routines and want to use them in Rules?

In the end, isn’t the ST APP produced by SmartThings (Samsung) and would comply to a common JSON format.

Good for the Product Management team on SmartThings to consider.