Sitemap configurable Timer and Astrotimer (Timeclock, Astrotimeclock)

Here i show you my implementation and concept of a timer and astrotimer (i call it timeclock / astrotimeclock) setup build with rules, groups and a naming-convention.
With this concept you are able to configure your time- and astroclocks as well as the mapping of your items to the specific clocks completely in your sitemap (or Habpanel) without writing code.
You can get the full example code here:
For openHAB 2: GitHub - ModuloFS/openhab_example_timeclock: This is an example of realizing a timeclock functionality in openhab.

For openHAB 3: GitHub - ModuloFS/OH3_example_timeclock

How to use this example

  1. Install the Astro-Binding and add your location to the Astro.things file.
  2. Optionally you can install a persistence service like influxDB to store your selections beyond a systemrestart.
  3. Copy all files from my github repository in your openHAB setup.
  4. Initialize all the items which are used by the timeclock and the astrotimeclock internally by switching the item “DEBUG_ResetTimeclock” and “DEBUG_ResetAstroclock” to ON once. (You can do that through the openHAB console or by creating a switch in your sitemap)
  5. Initialize each of the item-timeclock-mapping-items in the example sitemap under “Timeclock Mappings” and map each item either to a timeclock or to no timeclock.

A example of how to use this timeclock-setup you can find in the Timeclock_Test.sitemap and Timeclock_Test.items.

How to configure your Items

You have your normal item which you want to switch with a timeclock:

Switch GF_Livingroom_tablelamp (gTimeclock)


This item you have to add to the group “gTimeclock”.

Then you have to add an additional item which stores and indicates the timeclock mapping of the item above:

Number TIMER_GF_Livingroom_tablelamp (gTimeclockSelection, gTimeclockMemory)


For this item it is important that you name it exactly the same as the item you want to map, with the prefix “TIMER_”. Additionally you have to add this item, which is always of type Number, to the groups “gTimeclockSelection” and “gTimeclockMemory”. The group “gTimeclockMemory” is to store your selection of the mapping in a database.

At this example you have four different timeclock-types on which you can map your items.

  1. Timeclock 1/2: A normal Timeclock with two different switchtimes within a week
  2. Astrotimeclock 1/2: A Astrotimeclock which you can define switchphases at sunset as well as switchphases at sunrsie as well as switchphase between sunset and sunrise. This is good for decoration lamps for example.
  3. Astrotimeclock Rollershutter 1/2: A standard astrotimeclock with a switchtime at sunset and a switchtime at sunrise. This is good for Rollershuttercontrol
  4. Calendar 1/2: Timetrigger via calendar events. This is realized with the items: “LOCAL_Kalender_1” and “LOCAL_Kalender_2” for the mappings Calendar 1 and Calendar 2. If you switch this items to ON, then all mapped items are switched ON or DOWN, depending if its a switch or a rollershutter. If they switched OFF the all mapped items are switched OFF or UP.

This is the rule where all the magic happens:

val Number SCHALTUHR_1 = 1.0
val Number SCHALTUHR_2  = 2.0
val Number ASTRO_1  = 10.0
val Number ASTRO_2  = 11.0
val Number KALENDER_1 = 20.0
val Number KALENDER_2 = 21.0

val Number ASTRO_ROLLO_1 = 30.0
val Number ASTRO_ROLLO_2 = 31.0


rule "Timeclock_evaluation"

when

    Member of gTimeclockTrigger received command

then

// check if a rule is already running
while (LOCAL_RULELOCK.state == ON)
{
    Thread::sleep(3000)
}

// set the Rulelock to block a second ruleexecution of "Timeclock_evaluation"
LOCAL_RULELOCK.sendCommand(ON)

    // Loop through all items (member of group gTimeclock), witch can maped to a timeclock.
    gTimeclock.members.forEach[timeclock_item|{
        
        // Loop through all items (member of group gTimeclockselection), whitch contains the timeclockmapping to each item.
        val selection_item = gTimeclockSelection.members.findFirst[i|i.name == "TIMER_"+timeclock_item.name] as NumberItem

        // Check if a item was found at all with the findFirst method
        if(selection_item !== null)
        {
            // Check if the actual item (temporary stored in timeclock_item) is maped to the matching timeclock
            if( ((selection_item.state == SCHALTUHR_1) && (triggeringItem.name == "LOCAL_Timersignal_1")) ||
                ((selection_item.state == SCHALTUHR_2) && (triggeringItem.name == "LOCAL_Timersignal_2")) ||
                ((selection_item.state == ASTRO_1) && (triggeringItem.name == "LOCAL_Astrotrigger_1")) ||
                ((selection_item.state == ASTRO_2) && (triggeringItem.name == "LOCAL_Astrotrigger_2")) ||
                ((selection_item.state == KALENDER_1) && (triggeringItem.name == "LOCAL_Kalender_1")) ||
                ((selection_item.state == KALENDER_2) && (triggeringItem.name == "LOCAL_Kalender_2")) ||
                ((selection_item.state == ASTRO_ROLLO_1) && (triggeringItem.name == "LOCAL_Rollo_Astrotrigger_1")) ||
                ((selection_item.state == ASTRO_ROLLO_2) && (triggeringItem.name == "LOCAL_Rollo_Astrotrigger_2")) )
            {
                // The actual item matches to a timeclock, so the switch command has to be executed
                // Here i use the implicit variable for the triggering item
                if(receivedCommand == ON) 
                {
                    // You can control Switches, Dimmers and Color items, as well as Rollershutter
                    if(timeclock_item.type != "Rollershutter") timeclock_item.sendCommand(ON)
                    else timeclock_item.sendCommand(DOWN)
                }
                else 
                {
                    // You can control Switches, Dimmers and Color items, as well as Rollershutter
                    if(timeclock_item.type != "Rollershutter") timeclock_item.sendCommand(OFF)
                    else timeclock_item.sendCommand(UP)
                }
                // Waittime is optional and im my case its for my RF-Outlets whitch need some time between each switching cycle
                Thread::sleep(1200)
            }
        }

    }]

// reset the Rulelock to enable the ruleexecution of "Timeclock_evaluation"
LOCAL_RULELOCK.sendCommand(OFF)

end

In this Rule you have two loops. The first (outer-) loop loops through the group “gTimeclock”. This group contains all items that can be assigned to a timeclock (Timeclock_1/SCHALTUHR_1, Astrotimeclock_1/ASTRO_1, usw…).
The second (inner-) loop loops through the group “gTimeclockSelection”. This group contains all items that mapps all the items to the different timeclocks. So each of the item in the first loop has a related item in the second loop with the additional prefix “TIMER_”.
Now if a pair is found in this line:

val selection_item = gTimeclockSelection.members.findFirst[i|i.name == "TIMER_"+timeclock_item.name] as NumberItem

The mapping information is checked and if necessary a switching command is executed in the following lines of the rule.

4 Likes

Hi,

thanks a lot for your great work! Your Timer is what i’ve searched for.

I’ve tried to set it up as you descriebed, but i get the following error:

==> /var/log/openhab2/openhab.log <==

2019-12-23 22:07:30.039 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Astrotimeclock_backend': Could not cast NULL to org.eclipse.smarthome.core.library.types.DecimalType; line 100, column 43, length 47

2019-12-23 22:08:00.100 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Timeclock_Frontend': d != java.lang.String

What did i wrong?

Hello,

it looks like you have not initialized all your items which are used by the Timeclocks. For example in your first described error i think the item “LOCAL_TriggerdelaySunset_1” has no value.

The item LOCAL_TriggerdelaySunset_1 is initialized. Se also line 24 in your Astrotimeclock.rules:

postUpdate(LOCAL_TriggerdelaySunset_1, 60.0)

I use the same config-files as in your github repository.

Thanks for your help!

BW

Are you sure you switched the item “DEBUG_ResetAstroclock” to ON once, so that the Astrotimeclock_Initialisiation rule run once and initialized your items?
Because if i set the item “LOCAL_TriggerdelaySunset_1” to NULL in my setup i get exactly your error message.

Is your setup working now?

Hi,

i’ve stopped trying it with your timer. Now i’ve wrote my own code with fixed times.

BW Maximilian

!! CODE-UPDATE !!

At the first version of this code i have used the concurency guard java.util.concurrent.locks.ReentrantLock to prevent multible executions of the Rule: “Timeclock_evaluation”. This is necessary for example if you are using multible RF-Outlets and you do not want so start multible sending commands at the same time.

I had some problems recently so that either the lock-object was not known by the rule engine at the start of openHAB or the lock-object was not unlocked anymore after a while. Both results in the problem that openHAB never executes the “Timeclock_evaluation” rule anymore and i had to restart openHAB.

So because of that i changed the locking system and now i am using a Switch-Item as a global variable:

Switch LOCAL_RULELOCK   {expire="10m,state=OFF"}

If the “Timeclock_evaluation” rule fires the first time, the rule sets this item to ON. If the execution is done, the item is set back to OFF. During the ON-time every additional execution of that rule ends up in a while-loop.
To prevent a deadlock by accidentally not reseting the item-state to OFF, i added the Expire-Binding to the item. If the item is more than 10 minutes in the ON-State it is reseted to OFF.

// check if a rule is already running
while (LOCAL_RULELOCK.state == ON)
{
    Thread::sleep(3000)
}

// set the Rulelock to block a second ruleexecution of "Timeclock_evaluation"
LOCAL_RULELOCK.sendCommand(ON)

... RULE CODE ...

// reset the Rulelock to enable the ruleexecution of "Timeclock_evaluation"
LOCAL_RULELOCK.sendCommand(OFF)
1 Like

@ModuloFS
I’m using your timeclock rules for some month now and recently upgraded to OpenHab 3. Unfortunately I’m getting errors with your rules and they are not working. In the Release Notes of OpenHab 3 there is mentioned, that the the Java Time API is now used and therefor rules like “now.GetMinuteOfDay” is no longer available.

I tried to adapt your rules to OpenHab 3 but I was not successful. Could you please have a look on this? This would be great!

Best regards,
Markus

Hello Markus,

Thank you for your feedback!

Unfortuanately till now i had no time to migrate to OH3 to test my timeclocksolution.

I try to fix this problem as fast as possible!

Hello @markus84

i think i found the problem and fixed it. I have created a new repository for the code for openHAB 3. You can find it there: GitHub - ModuloFS/OH3_example_timeclock

The changes were made in the Astrotimeclock.rules and the Timeclock.rules files. I have marked the changed code with “// new due to OH3”.

Please give me a feedback if it is working in your setup.

1 Like

@ModuloFS thank you for your fast response and your fast fix for OH3. It works great for my setup! I whish you all the best for 2021.

I am glad to hear that it works!

Wish you all the best for 2021 too!