How can I kill a looping driver

I have a lot of coding experience, but the closest to Groovy is C, and the closest event driven environment is the old Visual Basic stuff. All the environments I've coded in so far (from IBM mainframe operating system stuff to TV remote control chips) have had some pretty good debugging capabilities, including the ability to single step thru code.

I'm trying to get up to speed on HE and Groovy. I can understand a lot of the driver code because, to me, the Groovy syntax is reasonably close to C syntax.

Where I'm struggling is understanding how to test/debug code. It looks like the main way is to write log messages. Am I correct in that there is no way to single step thru code?

It's only a matter of time before I try to test some code that goes into a never-ending loop due to a programming error, for example, a while loop whose break logic never becomes true. When that happens, how can I kill the code/driver/instance/whatever-needs-to-be-killed to stop the loop?

You're correct, there isn't a debugger for the Groovy environment, just the system logs.

I did have an issue with a runaway loop once, I think (not certain, it was a while ago) the solution was just to remove the instance of the app and that killed it.

I don't think infinite loops are as common in Groovy as they are in C since you are usually looping over lists instead of using counters to manually iterate through things.

The diagnostic tool offers a Safe Mode that will help you stop the kind of loop you're thinking of.

And yes, debug lines are your best tool, there is no native step through method.

2 Likes

And of course, the first time I tried to test the driver I'm working on, it went into an infinite loop that included a sendEvent call. HE terminated it after a few seconds. Something about too many events.

If it gets really out of hand you can always reboot the hub. Hopefully it is not something that restarts after booting. If it is, you could use the Safe Mode as explained above to prevent it from running right away I think.

:thinking:

...

(I''m just joking. Been there, done that)

3 Likes

been down this rabbit hole on a few occassions. I 'disable' the app

then reboot, and click the gear to the left of the app then scroll all the way to the bottom and 'remove'. Disabling the app - and I'm gonna take heat for this - does not actually stop some loop conditions - so the reboot causes the app not to fire up, allowing it to get term'd/removed.

1 Like

The toughest part for me is getting in the "object oriented" mindset. 99% of the code I've written is procedural, and the vast majority of that is mainframe assembler. I understand the IF/THEN, SWITCH, WHILE, FOR, variables, operators, and other similar procedural constructs, but the OO stuff is killing me.

I'm playing around with the user "virtual window shades" driver as my first project. I'm hoping to make it act more like a real motorized shade. Should be simple enough. Only six commands and two attributes. I have a couple of the commands (OPEN and CLOSE) working the way I want. Everything shows up correctly on the device details page, including the windowShade and position attributes/values. I can get the last position value to figure out my "starting point" on the OPEN and CLOSE commands. But for the last two hours, I've been stumped trying to get the windowShade value ("open", "close", etc.). This call...

string shadeState = device.currentValue("windowShade")

results in...

dev:522023-08-29 04:15:48.121 PMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_mydriver_Virtual_Window_Shade_633.string() is applicable for argument types: (null) values: [null] Possible solutions: toString(), toString(), toString(), print(java.lang.Object), print(java.lang.Object), print(java.io.PrintWriter) on line 197 (method stopPositionChange)

But the device detail screen implies to me that there is a correct value available for the attribute. I do the same thing to get the position, and that works.

String shadeState
Capitol S
Or just use def or nothing
Groovy has loose types like JavaScript.
I hate it honestly but it comes in handy sometimes.

Capitalizing the S got rid of the error, but now it always returns a value of null.

There are some basic fundamentals (maybe a lot) I haven't grasped yet.

I'm attempting to modify a "Window Shade" class driver. I assume everything I need to work with that class is either always available or are brought in by this statement in the metadata block...

capability "Window Shade"

According to the doc, the class has two attributes: windowShade (an enumerated string value, e.g., "open") and position (an integer value).

My code sets the position with this...

sendEvent( name: "position", value: currPos )

...which seems to work fine (expected value shown on the device details page). Then when the driver is next driven for the same device, the last known position value is retrieved with this...

lastPos = device.currentValue("position")

...which also workes fine. I thought similar code would work for setting/getting the windowShade attribute value...

sendEvent( name: "windowShade", value: "${reqState}" )

...and...

lastState = device.currentValue("windowShade")

The sendEvent seems to work okay (device detail page shows expected value), but the windowShade value always returns null, even if it is executed in the same driver instance immediately after the sendEvent call.

Something tells me I need to do something else to save off the attribute values across instances from the same device, but if that's true, why does it work for the position attribute?

FYI, from the Hubitat documentation.

There’s no space

Most (all?) work with or without the space, this is possibly a compatibility thing for converted ST code.

@user2164 is the attribute showing on the device page?

image

Not sure what you mean by "same driver instance"??? Same function?

No, the sendEvent saves them as long as they are defined in the capability or explicitly. that's its purpose.

Have you tried this:

log.debug device.currentValue("windowShade")

Or you might need to do this

lastState = device.currentValue(evt.name).toString()

Although I am only doing that in comparisons to make sure both values are String type.

Changing "Window Shade" to "WindowShade" didn't help. It was "Window Shade" in the original driver I started with. I'm not used to languages being that "forgiving".

My terminology is probably wrong for this environment. By same driver instance, I meant in the same function call.

My code was...

shadeState = device.currentValue("windowShade")
log.debug( "Current shade state: ${windowShade}" )

...and that always resulted in this log message...

Current shade state: null

I added your line to make it this...

shadeState = device.currentValue("windowShade")
log.debug( "Current shade state: ${windowShade}" )
log.debug device.currentValue("windowShade")

...which resulted in this...

open
Current shade state: null

...so your suggested log message displayed the correct value. Looks like the windowShade value is being correctly saved. So is the problem in my "currentValue" line or my log.debug line?

FYI... the statement...

lastState = device.currentValue(evt.name).toString()

...resulted in this error...

java.lang.NullPointerException: Cannot get property 'name' on null object on line 209 (method stopPositionChange)

1 Like

Interesting - I’ve never tried it with a space!

:person_facepalming: :laughing:

Try this

shadeState = device.currentValue("windowShade")
log.debug( "Current shade state: ${shadeState}" )

You were setting one variable and then using a different one on the log message.


That was supposed to be

lastState = device.currentValue("windowShade").toString()
1 Like

That was it. Working as expected now. Not the first time (and won't be the last) that I've missed the obvious because I've been staring at the code too long.

Thanks for the help.

1 Like

As a professional PHP developer; I can confirm this happens to me all the time! :slight_smile:

1 Like