RM Needs an elegant method to use State Transitions!

I know this has been brought up before, but RM is being held back badly (imo) by the lack of an elegant method to trigger rules based on state transitions.

The classic example is Mode transitions - I have a bunch of rules that I only want to run if the Mode has changed from Night to Home. And others that I only want to run if the mode changes from Away to Home. eg:

Away to Home: Unlock all doors immediately
Night to Home: Unlock all doors only when the Dining Room Sensor detects motion
Home to Away: Lock all doors after 60 seconds

I know this ability to trigger transitions is in Simple Rules, however, they are fairly useless for many automation scenarios. You cant even populate a Global Variable with them. There are workarounds to this, but they are a royal PITA. eg for me to implement the above door lock scenario required the following:

  1. A Virtual Switch (Night Mode Trigger w/ 5s auto off)
  2. A Simple rule to Flip the Virtual Switch when Mode Transitions from Night to Home
  3. A global variable (Previous Mode)
  4. An RM rule to monitor the Virtual Switch and Mode Changes then Populate the GV with Either Night or Away depending on if the VS had been flipped On or not.

All this just so I can my Lock rule can take the appropriate action based on Mode specific transitions!

To be blunt, it's just daft that we need to jump through burning firey hoops to utilise a basic tenant of automation in HE's most advanced automation builder.

To do this, HE wouldn't even need a new trigger type, just have the "Changes" Trigger capture the before and after states being monitored and make those states available in the rule as a Local Variable.

I might be missing something, but why not do something simpler like this instead? [EDIT: I forgot to mention that currentMode and lastMode are intended here to be string variables; local would work in this case, though you could make them global if you want/need.]

Trigger: Mode *changed*

Actions:

Set currentMode to %value%
IF (lastMode is "Away" AND Mode is "Home") THEN
  Unlock: Lock 1, Lock 2, Lock 3
ELSE-IF (lastMode is "Night" AND Mode is "Home") THEN
  Wait for event: Dining Room Motion Active (maybe add a timeout and check it?)
  Unlock: Lock 1, Lock 2, Lock 3
ELSE-IF (lastMode is "Home" AND Mode is "Away") THEN
  Wait for event: elapsed time -> 0:01:00
  Lock: Lock 1, Lock 2, Lock 3
END-IF
Set variable lastMode to currentMode

This seems a lot simpler than the virtual switch and multiple apps, though you could certainly also break this down into smaller rules too. But basically, the idea is to capture the current mode in a variable (you wouldn't need to do this if there weren't "Waits," but it's possible a timeout will change the value of the built-in %value% variable that would otherwise contain the mode name with this trigger, so it's safer to do it this way), then set another variable to track the "last" mode (current at the time the rule executes, but checked next time so it's the previous one).

Alternatively, you could do this with a series of smaller rules and even get rid of the variable by exploiting the behavior of "Wait" actions. For example,

Trigger: Mode *changed* (EDIT: Nevermind, you'd be need specific modes here: all except thr one you're waiting on. Can't have it retriggered in that case.)

Actions:

IF (Mode is Away) THEN
  Wait for event: Mode is Home
  Unlock: Lock 1, Lock 2, Lock 3
END-IF

Similar for all your other sequences.

A retrigger cancels all "waits," and you can use a conditional chained with a "Wait" like this to test for a specific series of modes like you want.

I'm not saying I don't understand your feature request or see a possible use for it, but there's often already a way to do things (or multiple ways), and I think we're less likely to get that kind of request granted. :slight_smile: So, I thought I'd point a couple other methods out if you haven't already thought of them. (Honestly just thought of that second one as I was writing this post, and it seems pretty elegant if you ask me--not a huge fan of the "changed" trigger, but it is the best way I can see to cancel those waits when you need to.) Good luck either way!

2 Likes

Where are you getting this from? There's nothing in RM that I can find called this?

I Have multiple rules that trigger based on Mode changes so setting a global variable with the "last mode" via a single rule is useful as I can just compare against that.

If RM made the "current mode" (or state) and "previous mode" (or state) available as local variables within any rule that used a **changed ** trigger, I could just do the comparison within each rule that needed it without resorting to setting Global variables and generally hacking in workarounds.

Your suggestions are more elegant than my brute force method (Im not a programmer, not even close), but it shouldn't be so darn hard to do this sort of thing. HE is already able to detect the state change, so just store the results and expose the previous-state and current-state variables to us users who arent very good at coding.

Thanks for this, it was quite useful, I was able to simplify my hack job quite a bit.

IF (Mode is Night(F) [FALSE]) THEN
	Wait for event: Mode becomes Home
	Set PreviousMode to 'Night'
ELSE-IF (Mode is Away(F) [FALSE]) THEN
	Wait for event: Mode becomes Home
	Set PreviousMode to 'Away'
END-IF

Sorry, I forgot to explain that I intended for lastMode to be local variable in this rule (same with currentMode). You could also make them global variables, and of course, you may prefer one over the other depending on what use you have for them where. (You could even separate the logic of tracking this out into a separate rule; I was thinking local here since my example, perhaps simpler than any of your real-world cases, can fit them all into one without getting overly complex.)

The example in your second post should work, too!

1 Like

Yep, just tested it and works great.

TBH, this sort of thing just doesnt occur to non-coders - RM is great but imo it needs to make this sort of thing simpler as I suggested earlier.

I personally find Simple Rules, Notifications, and Basic rules useless for anything requiring more than "IF THIS, THEN THAT". If RM's triggers can act upon something, it should expose that info to the Rule being written.

While I have no problem with the idea of automations fired by state transitions, this idea has little to do with RM. The examples shown above illustrate the issue: To trigger from a state transition requires (a) remembering a state, and (b) recognizing a specific new state for a specific prior state.

RM is much simpler than that, being triggered by events with no regards to saved and compared state information. As @bertabcd1234 points out, it is possible to construct this using fairly primitive elements of RM. But, that doesn't really get to @dJOS desire.

It seems to me that what is needed is a state manager app of some sort. Its purpose would be to embody the concepts of state and state transitions. It's call to action could easily run the actions of an RM rule (there is API for this), so as not to burden it with all of that. It might be of interest to note that the very first released version of Rule Machine didn't do any actions at all. It simple reported that the evaluation of the rule was true or false. Later, that rule evaluation outcome became the trigger of actions; and even later, rule evaluation was further pushed into the actions themselves, leaving primitive event triggers to start the whole thing in motion.

I'd be very resistant to adding more complexity to RM, as would be required to support in the app itself this whole concept of state transition. But, a state manager app that accomplishes the same objective would be something quite doable, for a qualified Groovy app developer. Food for thought....

2 Likes

It does seem like a good idea, although it's a bit of a blunt object. When using "changed" triggers, RM is already monitoring that device state, why not just use a pair of local variable's in that rule to store the before and after values and expose them to the Actions part of the rule?

Those values are there. But it's just difficult in the UI to introduce a means of referring to them and their values. For example, one has to reference both the device, and a specific value for its prior value. That means a whole new set of selectors in the UI. That would be a huge mess in the current UI.

Effectively, there would need to be an entire section much like creating a trigger event, that creates a prior state (e.g. temperature < 20). Then there would have to be a means to access that state as an element in a condition.

I'm wondering about just dropping the same code that creates a trigger into a new app, where it would define the prior state. You'd define the prior state, the trigger condition (limited to whatever defines the prior state, but with different value), and the actions to run (from a rule).

1 Like

Fair enough.

That would be a nice solution. Then we could just use it to Populate / Manage Global variables as required.

Perhaps, and/or just fire a rule upon a transition occurring.

1 Like

Ah yes, that would be better.

1 Like

There was the beginning of just such an app just about 16 months ago:

2 Likes

OK, I listened: Check out Predicate Conditions in Rule 5.0.

I went round and round on different ways to approach this, but eventually realized that a State Transition can be described by two things: an initial state that must hold, and a transition from that state. Predicate Conditions define the initial state. The transition away from that is whatever you want it to be, and doesn't even have to relate specifically to the initial state.

Your examples of mode transitions is easily accomplished now.

Yep. Fixed. And, btw, you get credit for goading me into solving this. Thanks for your input.

7 Likes

Thank you, very very much appreciated. :sunglasses:

3 Likes

Oh boy, this implementation is amazing!!! I just rebuilt my first rule (started with a simpler rule) and it has greatly simplified it! Thank you so much! :+1:

From this:

to this:

:sunglasses:

2 Likes

Another example - this one uses the new Hub Variables (which are also awesome):

Before:

after:

1 Like