Impossible to compare global string variables in Rule 4

I'm trying to create a simple rule to autolock my Yale lock if left opened.
When I unlock my door, a rule saves the time into a global variable (Yale.main.unlocked).
When I lock my door, a rule saves the time into another global variable (Yale.main.locked)

I wanted to make a simple rule that, every 5 minutes, check if Yale.main.unlocked is different than Yale.main.locked
No need to check the lock itself.

If the strings are different (because normally, I close my door just after the entry), the rule will lock my door and set the unlocked time equal to the locked time (to avoid multiple locks).

But when I try to create the rule, there is no button to validate any comparison between global variables. Is it normal ? Those variables are string variables.

Why? If the lock is locked, it's locked. If it's unlocked, it's unlocked.

Hubitat is an event driven system, not a state driven one. Needlessly running "check-in" scripts to find out what the status of things is creates unnecessary workload for the hub and will slow down your other automations.

String variables can either match or not match. That's all. You are looking for a number variable.

Basically, I don't like that my lock stays unlocked. If somebody, for unknown reasons, forget to lock the door, I want that door locked.
That's the purpose of home automation in my case: I don't want to go physically to my main entrance to check is somebody left the door unlocked.

And with that rule, I don't check status of things (my lock in this case), but only variables. So, I don't think that rule will slow down my HE.

how can I see that those string variables match, then ?

Checking the "lock" (locked/unlocked) attribute of your lock does not poll/refresh the lock--you'd have to do that yourself--so it would do effectively the same thing you're doing now but with a lot less work. But either way is unlikely to work like what you want for that reason: it would be the same was watching for this attribute changing to unlocked and staying there for >5 minutes (no need to check the attribute itself every 5 minutes; your lock should report accurately, and if it doesn't, that's a problem and something neither method will fix).

So, to keep it simple, just a rule that lock the door if my lock reports an unlocked state, right ?

If you want to automatically lock your door if it stays unlocked for a certain anount of time, then yes, a rule like this should work:

trigger: lock *changed*

Actions:

IF (lock is Unlocked) THEN
  Delay 0:05:00 (cancelable)
  Lock lock
ELSE 
  Cancel Delayed Actions
END IF

Some people like to add a contact sensor to make sure the door is actually closed, or they may choose to just send a notification instead so they can investigate.

2 Likes

Thank you. I've a samsung magnet sensor that show me the state of the door. So, I'll merge it in the rule.

I did this. And this rule is far better than the built-in autolock feature of Yale locks because it discriminates the state of the door (open or closed) + notification.

for me, it's a safety feature because it solves my problem (door kept unlocked) when kids are coming and forgot to lock the door when they leave the house...

*Edit: tested in real: perfect !

autolock%20result

1 Like

Sorry to thread necro but I'm researching rules for locks. I've seen code like this for rules and, to me, it makes absolutely no sense programmatically. How can that code ever cancel the delayed actions if the delay and the cancel are mutually exclusive code paths? If the IF evaluates true then you will run the delay and the rule stops processing. If the IF evaluates false then you execute a cancel of a delay that never happened, right?

Ask away! :slight_smile: Your question is really a general question about how the latest version of Rule Machine works, and as such, this thread may provide more information on what you're looking for:

Specifically, some examples early on show motion lighting automations with cancelable delays (you can ignore the equivalent rules in older versions--part of this guide is intended to help people upgrade). It's a totally different result but the same ultimate rule format.

But to summarize, here's how it works: your rule actions run any time an event fires that matches any trigger. Your trigger here is "lock *changed*," which means "lock locked" or "lock unlocked" (the only two possible states). Let's say the lock becomes unlocked. The IF... will evaluate to to true, so the delayed action will get scheduled. If nothing else happens, RM will follow through with that schedule and run the following action (locking the lock) at that time. If you lock the rule in the meantime, that matches the trigger, so the actions will again run. This time the IF... will evaluate to false, so the ELSE will match and run. What happens here is that the delayed action (technically the delay and everything after it, including locking the lock) gets cancelled. So, yes, they are in mutually exclusive blocks, but that's what you want to get this behavior--and it works because of your triggers. (A common mistake is people making rules like trigger on "motion active" instead of "motion changes" with an IF/ELSE similar to the above; one half of that rule will indeed never run.)

I appreciate your reply. And I promise, I've gone through the RM4.0 documentation many times now. The only way for your explanation to work is if the 2nd triggered instance of the rule running can cancel, without any kind of reference, the delayed actions in the 1st triggered running instance of rule. That's the problem I'm having with that explanation, it only makes sense if running instances of rules can interact with each other. Which isn't directly stated anywhere I've seen and is super counterintuitive to anyone with any kind of computer experience in their background.

I'm sorry for my incredulity, not trying to be disrespectful or have a bad tone, but is that really how it works? If I put a 'Cancel Delayed Actions' command in a rule, it cancels the delayed actions for all running instances of the rule? Without needing any kind of reference to the other running instances?

In this example, there would likely* not be multiple instances of the rule running at the same time. A rule is a single app (technically "child app" but that doesn't really matter here except that it does not invoke the "parent" RM app unless specifically called to, e.g., by using a global variable), and every execution of that app shares a single "app status," including scheduled jobs. This isn't RM-specific but is in general a description of how Hubitat apps (and SmartApps) work. The delayed action gets scheduled on the first execution (door unlocked) of the rule, then the app quits. When it re-awakens on the next trigger (door locked), the previously scheduled job is erased on the "Cancel." (I'm not sure if this is a common misconception or not, but I guess another mistake someone might make is thinking an app is always "running" in the background like a Windows app or service. The lifecycle of an app is such that it wakes up when needed, usually an event subscription, a trigger in the case of RM, or a scheduled job. Data that needs to be persisted has to be stored in the application state.)

*You actually can have multiple instances of the same app running at the same time, but it's usually not a good idea due to the shared state. This is one reason why to avoid creating rules with multiple complex triggers--to say nothing of how messy your Actions might need to be to determine why it's running and what you really want to do. If you ever get into developing apps on Hubitat, part of the reason both state and atomicState exist (you should only use one per app, but the difference is more or less that state might not be written out until the app exits, whereas atomicState will get written more or less immediately during the app execution but with a possible performance hit--neither relevant for scheduled jobs since those are stored separately, but an idea related to app lifecyles nonetheless).

tl;dr I think the shared state/status is the "reference" you found missing between the first and second executions of the same app (and the fact that multiple instances of the same app are not likely to be "running" at the same time).

Yeah, the app concept you lay out makes sense, and in that context the documentations meaning dramatically changes. But without that context the description of the RM rules is more akin to a script running on a trigger. So in our running example, you have a copy of the script running when the lock is unlocked and then another copy would be run when the lock is locked. Nothing in the documentation, to me, implies or is intuitively meaning that it's really an app that's just been resumed and the trigger really just causes that app to run the "rule code" again even though the previous run of that "rule code" could still be active (via delayed actions or repeating action loops?) inside that app.

I really appreciate the discussion and insight here. It will definitely make designing rules for my Hubitat simpler I think. This sheds a lot of light on the how and why of private boolean too.

Definitely going to re-write my current auto-relock rules now too. No need to monkey with a local variable to track if an existing instance of the rule is already running to prevent duplicate actions and notifications and whatnot.

Fun fact: sometimes you actually can do this in a rule to work around devices with wonky reporting. :slight_smile: For a while, a lot of Z-Wave contact sensors were generating duplicate open/close events in quick succession, and so people with rules that notified them of these events were also getting duplicate notifications. A temporary solution was to use a local variable to tell if the rule had recently been run (not technically whether it was still running, as its execution would likely be fairly quick and have finished before the duplicate event comes in, but all of this generally within dozens or hundreds of milliseconds).

The best solution here is really for the device to not send the duplicates in the first place (for Z-Wave, there are often two "command classes" it may use, the "basic" one and one geared more towards its specific purpose); if that's not possible, the driver ignoring whichever it doesn't need would also be better (I think this is what Hubitat ended up doing; normally the platform also filters out duplicate events unless you tell it not to as the driver author, but these were coming in so quick the first hadn't finished processing yet). But if all of this is out of your control--as this was for most people for a while here--working around it in an app/rule is about all you can do.

Oh, and a local variable works better than Private Boolean here, or at least that is what the RM author mentioned when this "debouncing" issue came up. They sound similar but are apparently implemented differently (not sure how; I assumed both went to state and not one to state and one to a setting, so maybe there is something else--like how they get set) in ways that matter here.

So here's what I ended up coming with that works ok for relocking a door and is a lot simpler than what I originally had. Basically triggers on any change to the contact sensor on the door or the lock itself. Checks on each start if the lock is not locked (which covers unlocked and unknown states) and that the door is closed. If so, then waits 10 minutes (I think ample time for people to come in and out repeatedly without lots of unnecessary locking and re-unlocking) and starts attempting to lock the door. And if any of those states change, then the rule cancels itself. This includes

Testing it, it seems to work for the most part. I have had an instance where the rule never completed. The last thing logged for it was "Action: Delay 0:10:00 (cancelable)" and nothing ever happened after that. Not sure what happened there. Manually running the rule again got the expected behavior. If I see that happen again, I'm contemplating setting up another rule that will trigger this rule every 5 minutes to catch the silent failures.

Also, now that the notifications app will repeat notifications, I don't need notification in the door locking rule. My original rule did double duty to notify me if doors stayed open for too long.

image

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.