Handling handlers dynamically

I'm working on some custom code that lets me handle room lighting with common code. It is able to dynamically schedule and unschedule events. Here's a short bit of code with a bunch of stuff cut out to make it easier to discuss.

def roomHandler(evt) {
	def counter = state.("${evt.room}Counter") ?: 0
	def cooldownHandler = evt.room + 'CooldownHandler'
	def delay = evt.delay
	def duration = evt.duration
	def del = "00" + delay%60
	def dur = "00" + duration%60

	unschedule(cooldownHandler)
		
	switch (evt.value) {
		
		case "inactive":
		def cooldown = (delay / 2 + duration).toInteger()
		def cd = "00" + cooldown%60
		ll "Zone inactive (${cooldownHandler}), Cooldown: ${cooldown} (${Math.floor(cooldown/60).toInteger()}:${cd.substring(cd.length()-2)})"
		runIn(cooldown, cooldownHandler, [data: [value: "cooldown", room: evt.room, counter: counter, duration: duration]])
		break
	}
}

def mainCooldownHandler(evt) {
	def handler = evt.room + 'MotionHandler'
	def counter = evt.counter - 1
	state.("${evt.room}Counter") = counter
	def duration = evt.duration
	def dur = "00${duration%60}"
	ll "Decrmenting counter (${counter}) for ${evt.room} next check in ${Math.floor(duration/60).toInteger()}:${dur.substring(dur.length()-2)}"
	runIn(0, handler, [data: [value: "update", room: evt.room, counter: counter]])
}

def LRCooldownHandler(evt) {
	mainCooldownHandler(evt)
}

def KTNCooldownHandler(evt) {
	mainCooldownHandler(evt)
}

Basically I am creating a handler using runIn when motion in a room goes inactive. The handler is unique to each room (ex: Living Room = LRCoolDownHandler, Kitchen = KTNCoolDownHandler). I can then unschedule the handler if a new motion event is triggered for that room.

The issue I have is that the runIn requires a function to call. If I have a standard function then the unschedule event will unschedule all rooms. As a workaround I made a function for each room that just calls the main function. That way I can unschedule just the handler for the current room.

This works well and my rooms are responding as expected. The question I have is there a better way to handle the handlers? I'm sure there is but I'm not seeing it. Thoughts?

I believe this can be a string, and you could dynamically change its value before the call to runIn().

That's what I'm doing now. The problem is that I have to create a function for each string value. Those function then pass the data to the standard function. For example

def LRCooldownHandler(evt) {
	mainCooldownHandler(evt)
}

The LR handler (and all the others) just calls the main handler where I have the common code.

I was hoping for a way to pass them all to the same function but then be able to still unschedule them independently.

It isn't horrible but it seems there is probably a better solution.

I don't quite follow. If you have a dynamic handler, can't you pass its name in data, and then use that in unschdule()?

Sorry if I'm not explaining it well. At my day job they shut down my R&D group sometime ago and I've not been doing any serious coding for a long time. :wink:

What I'm saying is that right now I end up with functions like:

def LRCooldownHandler(evt) {
def KTNCooldownHandler(evt) {
def GARCooldownHandler(evt) {

These all have common code so they just hand off the data to mainCooldownHandler(). I was hoping to get rid of all the first room named handlers and just point to mainCooldownHandler. However, if I did that in the runIn then all the handlers would be removed because they would all be call mainCooldownHandler.

It isn't a huge issue, just trying to brush up on my coding while working on this project.

I'll take another look at unschedule. Maybe I can dig deeper in that and just unschedule the single events based on something else.

Without a separate handler, you couldn't do a separate unschedule(). At least, the separate handler can be quite simple, only calling the main handler.

It just seemed inelegant having each function only call another function.

My core code probably should have been structured differently but it seems to be working OK. I originally had the event driven parts in Rule Machine. I didn't plan on moving it over so soon but it just kind of happened for other reasons. Overall I'm happy with the way it is working. I was looking to see if there was a cleaner way to handle the situation.

RM does exactly the same thing for exactly the same reason... unschedule().

I’m still missing a dynamic piece then. Right now LRCooldownHandler is hard coded. It is called dynamically but each room has a written static function to call. RM must be calling something that is also dynamic.

At least it isn’t too unmanageable in my case. I think I’ll top out at 13 zones so I can hard code those.

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