Aqara FP2 no zones to trigger

The JSON approach with an Expression I mentioned above would be the best way to do this.

In reading through the example you provided, it sounds like you get a value similar to the following whenever the zoneState attribute changes. This is just a formatted version from the rule condition you shared:

[
  {
    "id": "1",
    "name": "Master Shower",
    "state": "not present"
  },
  {
    "id": "2",
    "name": "Master Bathtub",
    "state": "not present"
  }
]

But based on your latest comment, it sounds like the “Master Shower” entry with the id of 1 sometimes is in the first position and sometimes it’s swapped with “Master Bathtub” and in the second position. Is that right?

Example Snippet

In that case, the overall concept I mentioned still applies, but it would need to be a bit more fancy to handle the position changing. You could use something like the following to grab the “Master Shower” state by its unique id:

items = parseJson($AqaraPresenceText)	#// converts the string back into an object
shower = filter(items, x.id == 1)[0] 	#//Filter the list to just the item with the specific id and return that single matching item
equalText(shower.state, "present") 		#// return true if the state is 'present', otherwise false

How This Works

I included comments next to each line above, but here’s a breakdown:

  1. Takes the $AqaraPresenceText and converts it from text back into an object (list) and stores that in items

    items = parseJson($AqaraPresenceText)
    
    • items is an expression local variable, meaning that it only exists during the context of this Expression execution
    • This step makes it so we can filter on the list of items
  2. Filter the list of items to just the item that has an id of 1. And since the filtered list only has our matching item, we grab that first item.

    filteredItems = filter(items, x.id == 1)
    shower = filteredItems[0]
    
    • Sometimes it’s easier to think about it logically like two difference steps similar to immediately above.
    • First we filter the list to just the items we are interested in filter(), then we pick that first item from the list filteredItems[0].
    • For a refresher, check the post I quoted above as it explains the concept of lists and objects.
  3. Return a true/false based on if the state of our selected item is exactly “present”

    equalText(shower.state, "present")
    

The beauty of this approach is we can have a single rule that runs whenever the zoneState updates that sets all of our desired variables in rule. We then immediately have variables indicating if motion is active in the shower and if motion is active in the bathtub.

Full(ish) Example

Here’s an example of what this whole thing would look like.

Of course in my example, I don’t have a real Aqara FP2, so I’m simulating your example by using a $AqaraPresenceText variable… this is roughly equivalent to the existing rule screenshot you shared:

  • Trigger: Master Bath Presence & Light - zoneState updates
  • Flow: Set $ShowerBathPresenceText value using $context.event.value value

Then it just needs a Set Variable action for each motion/presence status that we want to record. So I created one for the Bathtub and one for the Shower from your example.

As noted above, this single rule takes care of recording both the Bathtub and Shower motion status. It will set each variable to true if the relevant item’s state is present, otherwise it’s false.

Expression Snippets

Here’s the expression snippets in text format for your reference and ease of copying:

Bathtub (id: 2)

items = parseJson($AqaraPresenceText) #// converts the string back into an object
bath = filter(items, x.id == 2)[0]    #// Filter the list to just the item with the specific id and return that single matching item
equalText(bath.state, "present")      #// return true if the state is 'present', otherwise false

Shower (id: 1)

items = parseJson($AqaraPresenceText)	#// converts the string back into an object
shower = filter(items, x.id == 1)[0] 	#// Filter the list to just the item with the specific id and return that single matching item
equalText(shower.state, "present") 		#// return true if the state is 'present', otherwise false

:bulb: You might have noticed that the expression are functionally the same. The only thing that matters is making sure to update the id value.

The usage of shower vs bath as the expression variable doesn’t actually matter since it is only used during function execution. You could just as easily used a generic name like item in both examples.

2 Likes