Cannot "finish" RM rule, RM page not offering "Done"

I'm trying to create a rule that will wait for a measurement then in response an event from a custom vehicle sensor in my garage.

I get to this point and the UI doesn't offer a button to complete the rule entry. There is no circling Icon telling me the Hub is thinking and it seems it will say like this forever (at least 10 minutes).

Am I missing something here?

No you are not. I had the same thing happen to me yesterday, had to delete the rule & start over. In my case, I believe I made some wrong choice in one of the drop-downs, it went into this mode and I couldnā€™t get back. See if either the ā€œCancel this Wait Eventā€ or ā€œCancel this Actionā€ work for you.

RM UI seems a little fragile. Itā€™s not forgiving at all. Iā€™ve had this a few times. I just start over.

2 Likes

2.2.5.131 / C7

@bravenel
It would have been nice but I tried several times with the same results. I even downloaded a the database and reloaded it... no luck.

The distance should return a number. I actually don't care what the numbers in this line of code as it will be addressed later on in the rule.

My notes on what I should enter for the rules: by using these I can enter the rule with NO mistakes to confuse the UI (assuming I'm careful).

C01 SAFETY GarageOpening+NoVehicle turns lights ON

Trigger:
   (contact) Garage OH Door open

Select Actions to Run:
(custom rule, actuator) requestMeasRM() on Garage Vehicle Detection
(wait for event, custom attributes, distance)     <------ stalled here.

stalled


IF (Garage Vehicle Detection not present)  AND
Time between Sunset and Sunrise(T) THEN
     Activate scenes: Accent Lights
     Dim: Exterior Lights: 100
END-IF

Make a rule that sets a variable to that custom attribute, and then log the variable, so we can see what's going on.

Oh, I didn't see what your problem is. I'll look at it.

What is the value of that attribute? What type of attribute is it? Show the device state.

Does it matter that the event "distance" is NULL most of the time?

My driver measures the distance from the ceiling to the vehicle roof (if there) else it returns the distance from the ceiling to the floor.
A short time after this measurements are made the distance is set to null indicating the measurement may no longer be valid.

When the rule is triggered it requests: requestMeasRM() on Garage Vehicle

The goal of the problem line is to wait for an event returned from the above measurement request.

It's got to be a Number attribute. How is it defined in the driver?

Driver code:

/**
 *  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
 *
 *
 *              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
 *
 */

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

metadata {
    definition (name: "Garage Ultrasonic v03", 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", "bool"
        attribute "lastActivity", "String"
        attribute "distance", "Integer"
    }

    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 ---

It's got to be "Number", not "Integer".

Sorry, In my mind they are were the same, I'll watch in the future.

Attribute types are weird ducks. RM is specifically looking for NUMBER in that context, and that's probably why it got hung up. I'll look into making that more robust.

3 Likes

I found I had done the same thing elsewhere in my code.

Would it be as simple as in the UI showing what RM will accept or requires? Or maybe that is not very simple.

Can the compiler or code parser limit the acceptable attribute types to those useable?

This is all very esoteric stuff. I don't have the time right now to drill into it again. For use in a Condition there has to be a comparison, and the only types that support that in RM are NUMBER, VECTOR3, and STRING. VECTOR3 is the 3-axis attribute.

1 Like

Recognizing that your time is limited, could someone please just put this statement in the RM documentation?

More like driver documentation. Drivers should use NUMBER for numbers, not Integer or Decimal or anything else.

3 Likes

I've seen that documented in a number of places (no pun intended). And I periodically know we should be using number, unfortunately periodically I forget as well :slight_smile:

However whomever chose number instead of integer should have had a good reason, like deeper into the language (Java / Groovy) there are more significant differences than jus the name.

This is correct. There is also a database schema involved with this issue. I went through all of this at one point when dealing with RM custom attributes. And there are conventions used in the built-in drivers that may not prevail in user drivers. Suffice it to say, there are a number of 'types' in Java/Groovy that are not applicable as attribute types in driver metadata (bool is another example).

1 Like

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