Rule with timeout not acting as expected

I have a rule that is to test if a vehicle is in the garage triggered by the garage door opening.
The measuring device that tests if a vehicle is there takes a few seconds, maybe more. So I put a timeout for 1 minute on action.
My issue:
It seems the 1 minute timeout seems to delay rule processing regardless of if the "vehiclePresent" is returned or not.
I suspect a "cancelable" attribute might be in order but I can't figure how to add this in the editing.
Or perhaps I don't understand how the timeout works.

Any suggestions?
Thanks
John

a Rule 5.1

app:4127	2022-12-15 17:45:25.137	infoAction: END-IF
app:4127	2022-12-15 17:45:25.106	infoAction: Dim: Foyer Light: 40
app:4127	2022-12-15 17:45:25.065	infoAction: Dim: Lucy: 60
app:4127	2022-12-15 17:45:24.913	infoAction: Dim: Exterior Lights: 100
app:4127	2022-12-15 17:45:23.893	infoAction: Activate scenes: Accent Lights
app:4127	2022-12-15 17:45:23.796	infoAction: IF (Garage Vehicle Detection vehiclePresent(not present) not present(T) AND Time between Sunset(16:23) and Sunrise(07:11)(T) [TRUE]) THEN
app:4127	2022-12-15 17:45:23.611	infoWait over: timeout
app:4127	2022-12-15 17:45:23.601	infoWait Event: timeout timeout

app:4127	2022-12-15 17:44:23.508	infoAction: Wait for event: Last Event Device is vehiclePresent *changed* --> timeout: 0:01:00
app:4127	2022-12-15 17:44:23.448	infoAction: requestMeasRM() on Garage Vehicle Detection
app:4127	2022-12-15 17:44:23.338	infoEvent: Garage OH Sensor contact open

The rule is waiting for a "changed" event from the vehiclePresent sensor.
The timeout will wait one minute or until the vehiclePresent sends a changed event. Whichever is shorter.

Probably should use wait for condition. An event waits for event, so if already present when the wait is reached it waits. A condition will continue immediately.

1 Like

Thanks but I also want to have a limit to how long it waits.
I'll look further.

That's what I thought but the wait time is always 1 minute. I don't believe the response from the vehiclePresent sensor takes that long nor is that consistant.

What device is the vehiclePresent attribute on? In your rule, it's looking at the trigger device (or the last event device, which as far as I can see would always be this at that point). This appears to be a door sensor and seems unusual, but maybe you have a combined device type. In any case, have you tried just specifying the actual device? I don't think there's a reason to rely on this feature in this case (not that it shouldn't work if that is indeed the device).

You can have a timeout on wait for expression as well.

I called it wait for condition but it's wait for expression.

The vehiclePresent device is custom hardware with a Zigbee "radio" and custom driver.
I wrote it some time ago and the system seemed to work. Recently I started working on why there was a delay.
The rule "asks" for an update measurement. and vehiclePresent should be forced to "null" after the asked for measurement was sent.

You will see I'm not a good groovy coder, so my code is likely far from optimum.

/**
 *  Garage Ultrasonic Sensor
 *
 * 2020-12-25 - v02b - "saves" in hubitat and can request measurement via device page button.
 *                      able to compare rec'd distance value to threshold
 *              v02c -  add events putting results in db
 *              v02e -  release candidate, still needs testing.
 *                      with v02e everything seems to work.
 *              v02f -  added distance status
 *              v02g -  converted to PresenceSensor due to issues with RM and (bool?) custom attributes
 *              v02h -  Changed the variable echo to echo for clarity.
 *              v02j -  added runin to clear Distance and Presence after 5 minutes (as they could be invalid)
 *                        won't work.  We will have to count #OK.
 *						send  @. to make measurement
 *				v03  -  Add variable to count number of measurements made
 *              v04a  - distance was an integer
 *
 *              todo -  transfer initial configure to Hub instead of Arduino.
 *                   -  add ability to change "ping." in cc2430 and #OK. in Arduino.
 *                   -
 *                   -  clean up some of the log commands etc
 *          Change vehicle present to enum   present, not present, null
 *
 */

import hubitat.device.HubAction
import hubitat.device.HubMultiAction
import hubitat.device.Protocol

metadata {
    definition (name: "Garage Ultrasonic v04a", namespace: "johnrob", author: "various") {
        capability "Actuator"       // our device has commands...
        capability "Sensor"         // our device has attributes...
        capability "PresenceSensor" // ENUM["present", "not present"]
        capability "Configuration"  // capability "Configuration"  commands: configure()

        command "requestMeasRM"

        attribute "vehiclePresent", "enum", ["present", "not present","null"]
        //attribute "someOtherName", "enum", ["light", "dark"]
        attribute "lastActivity", "String"
        attribute "distance", "number"
    }

    preferences {           // see: Hubitat Notes (HTTP, driver and app).docx for more input options (there are lots of them)
        input name: "threshold", type: "num", title: "Presence Threshold (cm)", defaultValue: 200, range: "50..250", required: false
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
        input name: "txtEnable", type: "bool", title: "Enable descriptionecho logging", defaultValue: true
    }
}

// Parse incoming device messages to generate events
def parse(String description) {
    if (logEnable) log.debug " description is $description"
    state.lastRan = now()
//    runIn(300, clearOldData)   //seconds, watchdogAlarm,[overwrite: true])  // [] because overwrite is a map

    Map map = [:]

    def event = zigbee.getEvent(description)
    if (event) {
        if (txtEnable) log.debug " parsed zigbee event = '${event}"
        sendEvent(event)
    }

    else if (description?.startsWith("catchall:")) {
        if (logEnable) log.debug " catchall is $description"
    }


    else if (description?.startsWith("read attr -")) {          // our returned measurement is in this Map
        def descMap = zigbee.parseDescriptionAsMap(description)
        if (logEnable) log.debug " Desc Map: $descMap"
        if (descMap.clusterInt == 0) {
            def echo = descMap.value            // def = define untyped variable
            if (txtEnable) log.info " parsing '${echo}'"
            echo = echo.replace(".","").trim()
            if (echo.startsWith("!")) {
                echo = echo.replace("!","")
                sendEvent(name: "distance", value: echo, isStateChange: true, unit: "cm")

                int echoValue = Integer.parseInt(echo)
                int threshold = Integer.parseInt(threshold)

                if (txtEnable) log.info "echo=${echoValue}"

                if (echoValue > threshold) {
                    vehState = "not present"
                    log.info " > threshold}"
                }
                else{
                    vehState = "present"
                    if (txtEnable) log.info "${echo} < threshold}"
                }

                return sendEvent(name: "vehiclePresent", value: vehState, isStateChange: true)
            }
            if (echo.startsWith("ping")) return    // trailing . removed above
            else if (echo.startsWith("#OK")){
                clearOldData()        // by the time we get the next OK, the data will be obsolete.
                return
            }

            else log.warn "Not an attribute we can decode"
        }

    } // --- 2nd else if ---


    else {
        log.warn "DID NOT PARSE MESSAGE for description : $description"
        if (logEnable) log.debug zigbee.parseDescriptionAsMap(description)
    }

}   // --- parse ---

//def getecho(){ // read some attribute string from the device
//  if (txtEnable) log.info "gettext"
//    //zigbee.readAttribute(0x000, 0x0006) // gets the last thing the device tried to send to us
//    zigbee.readAttribute(0x000, 0x0010) // gets the last command the device heard us send
//}

def requestMeasRM() {
    sendHubCommand(new HubAction(sendtodevice("@."), Protocol.ZIGBEE))
}

def sendtodevice(String mystr){
    if (txtEnable) log.info "sending '${mystr}'"
    mystr=mystr.padRight(16,".") // mystr should be 16 bytes!
    def packed = hubitat.helper.HexUtils.byteArrayToHexString(mystr.getBytes())
    if (logEnable) log.info "sending '${mystr}', packed is ${packed}"

    def commandtosend = "he wattr 0x${device.deviceNetworkId} 8 0x000 0x010 0x42 {10"+packed+"}" // SAMPLELIGHT_ENDPOINT is defined as 8 in device code // the 10 on the end means 16 bytes length
    if (logEnable) log.debug "$commandtosend"
    return commandtosend
}

def sendCommand(String msg) {
    if (txtEnable) log.info "sendCommand - ${msg}"
    sendHubCommand(new HubAction(sendtodevice(msg), Protocol.ZIGBEE))  // "new" Creates a new HubAction object
}

def configure() {
    if (txtEnable) log.info "Configuring Reporting and Bindings."
    zigbee.onOffRefresh() + zigbee.onOffConfig()
}

def installed() {
    if (txtEnable) log.info "Executing 'installed()'"
    updated()
}

def initialize() {
    if (txtEnable) log.info "Executing 'initialize()'"
}

def updated() {
    if (txtEnable) log.info "Executing 'updated()'"

    if (logEnable) {
        log.info "Enabling Debug Logging for 30 minutes"
        runIn(1800,logsOff)
    } else {
        unschedule(logsoff)
    }
}

def now() {
    if(location.timeZone)
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
    else
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
    sendEvent(name: "lastActivity", value: now, displayed:false)
    result
}

def clearOldData() {
     sendEvent(name: "distance", value: "null", isStateChange: true, unit: "cm")
     sendEvent(name: "vehiclePresent", value: "null", isStateChange: true)
}

//  --- eof ---

Thanks for the help. I've been doing more testing and have been finding varying results with regards to timing. I need to investigate some more.

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