-
-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added ability to query the length of a given timer via keyName. #114
Conversation
…s: 1) allows user to re-queue the timer at the same or different time frame with the same or different instruction set or 2) allows user to make logical decisions regarding how much longer it will take until the timer executes at any given point. Example: An external garage door "close" timer is set for 30 minutes, but an internal garage door opens and interrupts this. The timer can be inspected and if the timer to execution time is less than 10 minutes, assume the car is going to leave shortly and extend the timer to another 10 minutes from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this is a feature that should extend beyond just TimerMgr.
If we create a Timer
class that consists of the OH timer and keeps the when
that gets created from helpers.createTimer
then we can get the ability to get the when
for any timer created and managed by OHRT, not just in TimerMgr.
Would you be up for that?
timerMgr.js
Outdated
*/ | ||
currentTimerLength(key) { | ||
if (key in this.timers) { | ||
return this.timers[key]['when'].toEpochSecond() - time.toZDT().toEpochSecond(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, this should return a time.Duration
instead of number of seconds.
return time.Duration.between(this.timers[key]['when'], time.toZDT());
...
return time.Duration.ofSeconds(0);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate to do this but it just occurred to me, does it make sense to return 0 if the timer doesn't exist? Shouldn't it return null
? I can go either way. Is there some use case where getting a 0 length duration makes sense for a Timer that doesn't exist?
As for the change to between, your approach is better. I wasn't thinking. now
should clearly be the first arguments. If the Timer has already passed we'll still get a negative duration but I think that's desireable. "How long since this timer ran?"
Hi Rich! Thanks for reviewing this change. I made the alterations you requested with one modification: I return a positive value as the Duration object so that the user can re-queue the timer with the current exact duration remaining. The example you gave would return a negative number and would then require a modification or abs() to re-queue. As for including the timer on the helper function, I think it's a great idea! However, since the openhab timer is returned by this function, we would have to wrap this return value in an object in order to return all the info correctly, eg:
I'll have to look at the scope at which this changes your other code, as I'm not super familiar with it yet. Would be happy to give it a try if you give this solution your blessing, however. |
Actually, what I was thinking was to moneky patch the timeout to the Timer class similarly to how ZonedDateTime is monkey patched in openhab-js. However, I don't know how easy that is to do with a Java class imported using If we can monkey patch then the only immediate changes would need to be in helpers. Then over time I can expose the Code wise I think it would look something like:
Assuming that works, as far as the down stream classes are concerned they are still getting an OH Timer Object and they won't need to change immediately. And TimerMgr won't need to handle storing the It might be worth while going upsteam and seeing if openhab-js or even openHAB itself would be willing to implement exposing the when. @florian-h05 WDT? In the short term, I absolutely will be accepting this PR. I'm just hoping to make it as universally applicable as possible without a lot of rework later. If you aren't willing to go down that path, that's cool and I'll merge and create an issue to remember to come back and make it more generic. |
I could imagine exposing this upstream in core, which however would create the problem, that we need to convert the Java ZDT to a JS ZDT. |
@rkoshak - Sure, I wasn't sure how deep into the framework you imagined this going. Just a note, if it is feasible to implement in either openhab-js or even OH, you're actually passing when as timeout:
So no need to set the when property in the post processing of the Timer object? Let me know if you go down the more deeply nested route, otherwise I can wrap it in a local object for use in these tools if you foresee any use for this approach there. It's been handy so far in my scripts! |
~~@florian-h05 Do you think core would be amenable to adding this to the Java class in the first place? It'd be a pretty small change over all with minimal impacts down stream? The further up stream this can be implemented I think the more who would benefit and the easier it would be to adopt. ~~ It's already there. :-) Though it's almost certainly a Java ZDT. How does openhab-js usually handle that sort of thing if wrapping the class isn't really an option?
The Timer class doesn't expose it. So even though we pass it to create the object, it's not made available to us in the object. But now that I look at the code, there is a That's not in the docs. I just tested this and it worked! So scratch my earlier suggestion. Remove storing
For consistency I think "get" makes more sense than "current" and since we are returning a Duration we should say that in the name too. "Length" is a little ambiguous. I'll add |
I love finding undocumented methods! Haha, great, all set on those changes. Thanks @rkoshak! I also added a commit (7798f3d and e816362) to add this method to the LoopingTimer, is this what you meant? For gatekeeper, would you expect it to return the currently executed timer's duration? Or don't add it there? |
For Gatekeeper I think this method is pretty useful too. But I think there it'd be useful to have two methods:
However, long term I wonder if it makes sense to hold on to a timestamp for when the last task in the queue was executed so we can see when it last ran also. I'm OK if this makes it into a separate PR so we don't have to delay merging this one. I think Gatekeeper needs a bit more thought. As I've been thinking about it though I really think the methods should return LoopingTimer is complicated. I think we'll need to be sure to document the behavior.
There is a brief period where a new timer is being created at the same time this method is called that we need to watch out for. |
loopingTimer.js
Outdated
return time.Duration.between(time.toZDT(), this.timer.getExecutionTime()); | ||
} | ||
|
||
return time.Duration.ofSeconds(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I think on it, we really should return null
if there is no timer.
loopingTimer.js
Outdated
* @returns {Duration} of time left in the current loop of the timer | ||
*/ | ||
getDuration() { | ||
if (this.timer && !this.hasTerminated()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the !hasTerminated
test. If the timer has terminated it means the loop has exited and this will return a negative duration telling us when the loop exited.
timerMgr.js
Outdated
return time.Duration.between(time.toZDT(), this.timers[key].getExecutionTime()); | ||
} | ||
|
||
return time.Duration.ofSeconds(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return null
instead of 0 seconds.
documentation; remove hasTerminated from loopingTimer
@rkoshak - I was thinking earlier today that null would be more useful; 0 second duration could be misleading. Great feedback, thanks! I added some more documentation, too, based on what you outlined for loopingtimer. |
Also, not sure how you want to handle:
I'm not as familiar with loopingtimer as I don't currently use it in my code, let me know what you'd like to see for that? |
For LoopingTimer, I think we just run with a straight forward implementation and if it causes problems I'll try to come up with something more clever. I don't necessarily want to go out of our way to fix a problem we don't even know is a problem. But to avoid the problem, unlike in the other classes, we won't be able to rely on |
Hmm, that's super difficult, I actually don't have an idea how to handle that without wrapping the class ... I think we need to advise the user to use |
Hey @rkoshak - I've lost track of where we are on this PR. Would you like me to take any additional steps before a merge? It sounds like the additional changes proposed are a bit out of scope of this iteration and this change as it currently stands could add a lot of value for people currently. Let me know! Should I also iterate the project version? Thanks! |
I thought you were still working this. The discussion on LoopingTimer can be handled later (please open an issue so it's not forgotten). But the implementation is pretty simple.
This avoids the timing problem most of the time. I want to get the |
Possible use cases:
Example: An external garage door "close" timer is set for 30 minutes, but an internal garage door opens and interrupts this. The timer can be inspected and if the time to execution is less than 10 minutes, assume the car is going to leave shortly and extend the timer to another 10 minutes from there.