Stop timer and reset to null. Structure of rule okay?

Hi everyone.
I have a question.
Want to have the possibility to reload the Playsound command for 10 Minutes.
If i Switch the button Virtell_Wiederholung_c in Habpanel with the command OFF, it will reload the Sound. If the 10 minutes are over, the timer ends without any Sound.
For this i have to set the timer after the 10 minutes to null.
Ist this programming okay or can i make it faster, shorter?

Here’s the rule:

var Timer Waschmaschine_timer = null

rule “Waschmaschine”

when

Item Waschmaschine received command OFF

then
if (now.getHourOfDay() >8 && now.getHourOfDay() <21){
say(“Die Waschmaschine ist fertig!”)
if (Virtuell_Wiederholung_c.state == OFF){
Virtuell_Wiederholung_c.sendCommand(ON)
logInfo(“Waschmaschine_Nachricht”,“Timer gestartet”)
Waschmaschine_timer = createTimer(now.plusMinutes(15)) [|Virtuell_Wiederholung_c.sendCommand(OFF)
Waschmaschine_timer = null]
logInfo(“Waschmaschine_Nachricht”,“Timer abgelaufen”)
}}
end

rule “Wiederholung_c”
when
Item Virtuell_Wiederholung_c changed from ON to OFF then
if (Waschmaschine_timer !== null){
Waschmaschine_timer.cancel
Waschmaschine_timer = null
say(“Die Waschmaschine ist fertig!”)
logInfo(“Waschmaschine_Nachricht”,“Timer abgebrochen”)
}
end

Thanks for your help,
Markus

How can i copy the rule text in right formatting, like in vsc?

hc_225

Nice, thanks!

var Timer Waschmaschine_timer = null

rule "Waschmaschine"

when

 Item Waschmaschine received command OFF

then
  if (now.getHourOfDay() >8 && now.getHourOfDay() <21){
     say("Die Waschmaschine ist fertig!") 
  if (Virtuell_Wiederholung_c.state == OFF){
      Virtuell_Wiederholung_c.sendCommand(ON)
      logInfo("Waschmaschine_Nachricht","Timer gestartet")
      Waschmaschine_timer = createTimer(now.plusMinutes(15)) [|Virtuell_Wiederholung_c.sendCommand(OFF)
      Waschmaschine_timer = null]
      logInfo("Waschmaschine_Nachricht","Timer abgelaufen")
}}
end

rule "Wiederholung_c" 

when

 Item Virtuell_Wiederholung_c changed from ON to OFF

then
 if (Waschmaschine_timer !== null){
     Waschmaschine_timer.cancel
     Waschmaschine_timer = null
     say("Die Waschmaschine ist fertig!")
     logInfo("Waschmaschine_Nachricht","Timer abgebrochen")
}
end

```php
your code goes here

Have a look at the expire binding
Much, much easier…

I also recommend using Expire based timers in situations like this.

But for completeness since Expire based timers don’t work in every situation:

  • I recommend centralizing all your time of day calculations (i.e. if(now.getHourOfDay...) because you will likely have more than one Rule that cares about the time of day. There is no sense in repeating code over and over for each Rule when you can write it only once. Design Pattern: Time Of Day

  • Does anything else call Virtuell_Wiederholung_c? If not there is no need for this separate Item (though you are already well set up to use the Expire binding with this separate Item). When one is using Timers you can put the contents of your Wiederholung_c rule into the body of the Timer and skip the separate Rule.

  • I don’t understand the logic. If the time is between 08:00 and 21:00 there is an audio announcement immediately when the washer finishes. All other times you wait 15 minutes before making the announcement. Why? I would expect you would want to avoid the announcement until 08:00 the following day to avoid being woken up. I just don’t see what the 15 minutes buys you in this context.

Given the above, where I to write this Rule:

var Timer waschmaschine_timer = null

rule "Waschmaschine"
when
    Item Waschmaschine received command OFF
then
    // Announce immediately during the day
    var whenToAnnounce = now

    // Wait until morning to announce if it is night or bed
    if(vTimeOfDay.state == "NIGHT" || vTimeOfDay.state == "BED") {
        if(now.getHourOfDay < 8) whenToAnnounce = now.withTimeAtStartOfDay.plusHours(8) // 08:00, could use a DateTime Item for this
        else whenToAnnounce = now.withTimeAtStartOfDay.plusDays(1).plusHours(8) // 08:00 the next day
    }

    waschmaschine_timer?.cancel // cancel a timer if there is one already set

    waschmaschine_timer = createTimer( whenToAnnounce, [ |
        say("Die Waschmaschine ist fertig!")
        waschmaschine_timer = null
    ])
end

The theory of operation is first we calculate when to announce when the washer is done. During the day we announce immediately (the default) and at night we wait until the next 08:00 to announce. Then we cancel the timer if there happens to be one running (the ? causes the Rules DSL to skip the line if waschmaschine_timer is null). Finally, we schedule a Timer to make the announcement. During the day whenToAnnounce will be some milliseconds in the past so the Timer will execute immediately. Otherwise, it will be scheduled to announce at the next 08:00.

If you truly do want to just delay the announcement by 15 minutes at night then you should use Expire based timers which will work very similar to what you are currently doing. But if you want to delay the announcement to the next day that requires custom timer periods and can only be implemented using regular old Timers.

2 Likes

Hi.
The virtuell_wiederholung item is a button in habpanel, which shows a new notification. The problem is that my wife sometimes doesn’t understand the spoken text from the tablet acustically. So she can repeat it for a time of 15 minutes by pressing the button. Otherwise it will be canceled.
The Time between 8 and 21 is correctly choosen for people who sleeps. For Switching the light for example i use your Time of day rule. It’s perfect.

Sorry the Smartphone converts zur Text in english automatically. I will make a new post

In that case neither your approach nor my approach does what you need.

You need:

  • A Switch Item with Expire to represent when the Timer is running during which time the announcement can be repeated
  • A separate Item on your HABpanel to press to have the announcement repeated
  • A Rule that triggers from the second Item that checks to see if the Switch Item is ON and if so go ahead and repeat the announcement. If not then ignore the button press.

Since you are likely to have more than one announcement this would apply to I recommend applying Design Pattern: Separation of Behaviors and Design Pattern: Gate Keeper to centralize all your announcement logic.

Then you can use something like the following which will repeat the last received announcement for up to 15 minutes:

Items:

String Announcement
Switch AnnouncementTimer { expire="15m,command=OFF" }
Switch RepeateAnnouncement "Repeate the last announcement"

Rules:

rule "New Announcement"
when
    Item Announcement received command
then
    logInfo("Announcement", receivedCommand.toString)

    if(vTimeOfDay.state != "NIGHT" && vTimeOfDay.state != "BED"){
        say(receivedCommand.toString)
        AnnouncementTimer.sendCommand(ON)
    }
end

rule "Repeat Last Announcement"
when
    Item RepeatAnnouncement received command
then
    if(AnnouncementTimer.state == ON) say(Announcement.state.toString)
    else logInfo("Announcement", "Too much time has passes since last announcement"
end

// to use the above in your rules
rule "Waschmaschine"
when
    Item Waschmaschine received command OFF
then
    Announcement.sendCommand("Die Waschmaschine ist fertig!")
end

Theory of operation: You have a trio of Items.

  • String Item you send command to with the text to announce
  • A Switch Item that gets set to ON for 15 minutes, this is the Timer
  • A Switch Item you put on your HABPanel to press to have the announcement repeated

To generate an announcement simply sendCommand("text to announce"). This triggers the “Announcement” rule which will log the announcement. If it isn’t night time it says the announcement and sets the Timer by sending it the ON command.

To repeat the last announcement the user sends a command to RepeatAnnouncement which checks to see if the Timer is running and if it is says the last announcement (i.e. the current state of Announcement).

Note: If it were me, I would just put Announcement on my HABPanel. Since the users have to interact with the panel in the first place to have the announcement repeated why not just put the text of the announcement there and save everyone that extra step and extra time?

1 Like

Hi Rich.
That’s perfect. It’s much easyer to make a lot of announcements in several rules. So much thanks for this.
But what happens, when a new announcements arrived in the 15 minutes of timer running?
Is there an option to play/say/write to string more than one announcemet?

There are always lots of options. You can do just about anything. But I would argue that the complexity added not just to your code but to your UI. How would you expect the user to choose which announcement to repeat?

You would have to:

  • create a list of the announcements over the past 15 minutes, though persistence might be useful here
  • have some sort of way for the user to choose what announcement to repeat
  • have some way for the announcements to fall off the list as they age out

We are talking orders of magnitude more complexity. I’d guess around 100 lines of Rules code might be required not counting the proforma (i.e. the rule “label” when triggers then end stuff).

The very first thing you will need to do is figure out the use case. How does the user choose what past announcement to repeat?

1 Like