Rule gets triggered twice

Perhaps this is caused by the behavior of your PIR. How often does it switch from OPEN to CLOSED and back when it detect movement? If it is almost immediately it could be the case that you end up with two copies of the rule running at the same time which would set up two timers if the timing falls just right.

You can avoid that by using a lock.

...
import java.util.concurrent.locks.ReentrantLock

val ReentrantLock lock = new ReentrantLock

rule "Garage PIR lighting"
when 
    Item ZONE9_GENERAL_STATUS changed to OPEN
then
    lock.lock
    try {
        logDebug("Lighting", "Garage PIR activated")
        ...
    }
    catch(Throwable t) {
        logError("Lighting", "Error processing ZONE9_GENERAL_STATUS update: " + t)
    }
    finally {
        lock.unlock
    }
end

The try/catch/finally is there so if there are any errors in your rule the lock will still get unlocked. Otherwise an error would basically kill this rule until you restart.

It this doesn’t work, it might be worth while looking at @bob_dickenson’s Proxy design pattern posted here.

It will provide a separation between the behavior of the PIR and the switching of your light so you can smooth out any erratic behavior caused by the PIR.