[SOLVED] Create a 'flexible' workweek

I want following rule to run only on certain days, not the whole week.

rule "Outside ON at sunrise"
when
        Channel "astro:sun:local:set#event" triggered START
then
        logInfo("ELEC", "buitenverlichting aan")
        sendCommand( VERL_Parking, ON)
end

I was thinking of creating somewhere (sitemap based) a frame where we can select “working days” and “hours”. And link this to a dummy switch (fe TIME_WORKWEEK, TIME_WORKSTART & TIME_WORKEND). Not sure how to link it with the dates? A kind of cron after every midnight to update this?
A good idea to go this way?


I was thinking of getting an end result as below.
The end time is another question mark. but let’s start easy; :wink:

rule "Outside ON at sunrise"
when
        Channel astro:sun:local:set#event triggered START
then
        if (TIME_WORKWEEK == ON) {
           logInfo("ELEC", "buitenverlichting aan")
           sendCommand( VERL_Parking, ON)
           }
end

rule "Outside OFF at end of workday"
when
        TIME_WORKEND is passed  // (???)
then
        if (TIME_WORKWEEK == ON) {
           logInfo("ELEC", "buitenverlichting uit")
           sendCommand( VERL_Parking, OFF)
           }
end

ps I’m a bit afraid that I’ll need to reinsert this every time that the server (service) restarts. This is something I still need to figure out, how to ‘remember certain status’.

Here’s one thought.

rule "Outside ON at sunrise"
when
        Channel astro:sun:local:set#event triggered START
then
        var Number day = now.getDayOfWeek
        if ((day == 1) || (day == 2) || (day == 3) || (day == 4) || (day == 5)) {
        if (TIME_WORKWEEK == ON) {
           logInfo("ELEC", "buitenverlichting aan")
           VERL_Parking.sendCommand(ON)
           }
		   else {
		   	VERL_Parking.sendCommand(OFF)
		   }
		}
end

Make another rule for your other dummy switches and adjust the days as needed.

1 Like

The question is: how do you get the information if the actual day is a workday and when the workday ends?
Are there any rules (not openHAB rules…) to calculate this information? Or is this information completely irregular?
One option would be to use a calendar and use the calendar binding to read the information daily.

Another solution is to use:

I started out with the gcal. Works great. But couldn’t get the sunset time working with that.

As I tried to describe in my orignal post, I was thinking to create some ‘switches’ that defines the week, and start/end times. This way, we can set this by the sitemap:

work_day_monday (ON or OFF)
work_day_tuesday (ON or OFF)
work_day_wednesday (ON or OFF)
work_day_thursday (ON or OFF)
work_day_friday (ON or OFF)
work_day_saturdday (ON or OFF)
work_day_sunday (ON or OFF)
work_time_start (1>24 : 1>60)
work_time_stop (1>24 : 1>60)

And then, with a cron rule update every day the status.

when 
  Time cron "0 5 0 ? * MON *"
then 
   if work_day_monday.state == ON {
      sendCommand( TIME_WORKWEEK, ON)
   else {
      sendCommand( TIME_WORKWEEK, OFF)
}

when 
  Time cron "0 5 0 ? * TUE *"
then 
   if work_day_tuesday.state == ON {
      sendCommand( TIME_WORKWEEK, ON)
   else {
      sendCommand( TIME_WORKWEEK, OFF)
}
...

For the time, I don’t have any clue yet. For this, i must investigate some time in the date/time formats. :blush:

Not sure what you think about this? Good, bad, one way to do it… :wink:

Just to give you some idea’s, this is what I use as a rule for time of day.

rule "Calculate time of day state"
when
    Time cron "0 * * ? * *"  //  runs every minuet 
then
    val String curr_time = now.toString("HH:mm")
    val String night_start = "00:00"
    var String morning_start = "06:00"
    val String day_start = (Sun_Dawn_Start.state as DateTimeType).format("%1$tH:%1$tM")
    val String evening_start = (Sun_Dusk_End.state as DateTimeType).format("%1$tH:%1$tM")
    val String midnight_time = "24:00"

    var new_val = "UNKNOWN"

    if (day_start < morning_start) {
        morning_start = day_start
    }
    switch true {
        case night_start <= curr_time && curr_time < morning_start:   new_val = "NIGHT"
        case morning_start <= curr_time && curr_time < day_start:     new_val = "MORNING"
        case day_start <= curr_time && curr_time < evening_start:     new_val = "DAY"
        case evening_start <= curr_time && curr_time < midnight_time: new_val = "EVENING"
    }

    if (Time_Of_Day.state.toString != new_val) {
        logInfo("Time_Of_Day", "Current time of day is now " + new_val)
        Time_Of_Day.sendCommand(new_val)
    }
    
end

I was thinking of creating a kind of ‘input form’ on the sitemap.
This so ‘everyone’ can change this as needed without going into the rules.

I don’t think its possible to change a rules value via input from the sitemap. You will need several rules and use a proxy switch with an if statement that determines if the rule get fired.

Another idea for time of day in a rule is use something like this

if((now.getHourOfDay() >= 8) && (now.getHourOfDay() <= 20)){
    TIME_WORKWEEK.sendCommand(ON)

Use this along with now.getDayOfWeek and your rule can check for both the day and time.

This a litte old, but I think perhaps looking at the AlarmClock example may help? It says OH1 but it just rules and items, so should work with OH2 as well.

Well, you can do it this way, but as you can see, will have to setup (minimal) 7 Items for weekday (if Sunday is possible part of workweek) plus two items for start and stop hour plus two items for start and stop minute. Simply use Number Items with minimum, maximum and step (I’m pretty sure you would not need precise Minute but maybe 5 minute steps or maybe quarters may suffice.) If you want flexible data, you will have to add 5 Items per weekday (ON/OFF, Start/End-hour/minute)
In question of the rule, you only would need one rule if you set the names of the Items carefully, e.g.

Group wwDay
Switch wwDay1 "Monday" (wwDay)
Switch wwDay2 "Tuesday" (wwDay)
Switch wwDay3 "Wednesday" (wwDay)
Switch wwDay4 "Thursday" (wwDay)
Switch wwDay5 "Friday" (wwDay)
Switch wwDay6 "Saturday" (wwDay)
Switch wwDay7 "Sunday" (wwDay)

Group wwStartHour
Number wwStartHour1 "Start hour Monday" (wwStartHour)
...
Group wwStartMinute
Number wwStartMinute1 "Start minute Monday" (wwStartMinute)
...
Group wwEndHour
Number wwendHour1 "End hour Monday" (wwStopHour)
...
Group wwEndMinute
Number wwEndMinute1 "End minute Monday" (wwStopMinute)
...
Switch Work "Work"

On Sitemap:

Switch item=wwDay1
Setpoint item=wwStartHour1 minValue=0 maxValue=23 step=1
Setpoint item=wwStartMinute1 minValue=0 maxValue=55 step=5
Setpoint item=wwEndHour1 minValue=0 maxValue=23 step=1
Setpoint item=wwEndMinute1 minValue=0 maxValue=55 step=5

Now a possible rule would be:

rule "set workstate"
when
    Time cron "0 0/5 * * * ?" // every day, every 5 minutes
then
    val acDay = now.getDayOfWeek.toString
    val day = wwDay.members.filter[d|d.name == "wwDay"+acDay].head.state
    val sH = wwStartHour.members.filter[d|d.name == "wwStartHour"+acDay].head.state
    val sM = wwStartMinute.members.filter[d|d.name == "wwStartMinute"+acDay].head.state
    val eH = wwEndHour.members.filter[d|d.name == "wwEndHour"+acDay].head.state
    val eM = wwEndMinute.members.filter[d|d.name == "wwEndMinute"+acDay].head.state
    if(day == ON) {
        if(now.getMinuteOfDay => sM + sH *60 && now.getMinuteOfDay < eM + eH * 60) 
            Work.postUpdate(ON)
        else
            Work.postUpdate(OFF)
    }
end

Of course it’s a rough piece of code…

1 Like

Probably the easiest is to put seven Switching on your sitemap, one for each day. When ON that sets that day as a work week.

Then apply the Time of Day DP (It’s not just for times of day) along the following lines (note, I recommend using a String Item instead of a Switch so you can add in other special day types like holidays or travel or the like):

  • name the workday Items using “WorkDay0” for Sunday and “WorkDay1” for Monday and so on
  • put the WorkDay Items into the WorkDays Group
rule "Calculate work day"
when
    Member of WorkDays changed or
    Time cron "0 5 * ? * *" or
    System started
then
    val workDayFlag = WorkDays.members.findFirst[ d | d.name = "WorkDay"+now.getDayOfWeek ]
    val newState = if(workDayFlag.state == ON) "WORK" else "OFF"

    if(WorkSate.state.toString != newState) WorkState.sendCommand(newState)
end

You can easily add in time start and time stop to the above Rule.

1 Like

now.getDayOfWeek will return 1 (for Monday) to 7 (for Sunday), according to joda.org. See https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeConstants.html

:slight_smile:

I could have sworn I saw 0 for Sunday. Guess I’m remembering some other program I used. Thanks!

What I’ve created so far concerning the days vs workweek:

werkweek.items

Group wwDay
Switch wwDay1          "Maandag"            <calendar>               (wwDay)
Switch wwDay2          "Dinsdag"            <calendar>               (wwDay)
Switch wwDay3          "Woensdag"           <calendar>               (wwDay)
Switch wwDay4          "Donderdag"          <calendar>               (wwDay)
Switch wwDay5          "Vrijdag"            <calendar>               (wwDay)
Switch wwDay6          "Zaterdag"           <calendar>               (wwDay)
Switch wwDay7          "Zondag"             <calendar>               (wwDay)
Switch wwDayFlag       "Werkweek [%d]"      <status>

Group wwStartHour
Number wwStartHour1    "Start uur [%d]"     <time>                   (wwStartHour)
Group wwStartMinute
Number wwStartMinute1  "Start minuut [%d]"  <time>                   (wwStartMinute)
Group wwEndHour
Number wwEndHour1      "Eind uur [%d]"      <time>                   (wwStopHour)
Group wwEndMinute
Number wwEndMinute1    "Eind minuut [%d]"   <time>                   (wwStopMinute)

default.sitemap

 Group item=werkweek label="Werkweek" icon="calendar" {
   Frame label="Werkdagen"  {
      Switch item=wwDay1
      Switch item=wwDay2
      Switch item=wwDay3
      Switch item=wwDay4
      Switch item=wwDay5
      Switch item=wwDay6
      Switch item=wwDay7
      }
   Frame label="Werktijden"  {
      Setpoint item=wwStartHour1 minValue=0 maxValue=23 step=1
      Setpoint item=wwStartMinute1 minValue=0 maxValue=55 step=5
      Setpoint item=wwEndHour1 minValue=0 maxValue=23 step=1
      Setpoint item=wwEndMinute1 minValue=0 maxValue=55 step=5
      }
   Frame label="Status" {
      Text item=wwDayFlag
      }
   }

werkweer.rules

rule "Calculate work day"
when
    Member of wwDay changed or
    Time cron "0 5 * ? * *" or
    System started
then
    val wwDayFlag = wwDay.members.findFirst[ d | d.name = "wwDay"+now.getDayOfWeek ]
    val newState = if(wwDayFlag.state == ON) "WORK" else "OFF"
    if(WorkSate.state.toString != newState) WorkState.sendCommand(newState)
end

Error
But when I change a Day, I’m getting following error in the log files:

2018-10-16 12:39:36.310 [ome.event.ItemCommandEvent] - Item ‘wwDay1’ received command OFF
2018-10-16 12:39:36.312 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘Calculate work day’: Couldn’t invoke ‘assignValueTo’ for feature JvmVoid: (eProxyURI: werkweek.rules#|::0.2.0.2.0.0.2.7.0.1.0.0::0::/2)
2018-10-16 12:39:36.313 [vent.ItemStateChangedEvent] - wwDay1 changed from ON to OFF

Not sure what I’m missing… :blush:

    val wwDayFlag = wwDay.members.findFirst[ d | d.name = "wwDay"+now.getDayOfWeek.toString ]

Typo… should be

if(WorkState.state.toString != newState) WorkState.sendCommand(newState)
//      ^

No change in the result… :blush:

rule "Calculate work day"
when
   Member of wwDay changed or
   Time cron "0 5 * ? * *" or
   System started
then
   val wwDayFlag = wwDay.members.findFirst[ d | d.name = "wwDay"+now.getDayOfWeek.toString ]
   val newState = if(wwDayFlag.state == ON) "WORK" else "OFF"
    if(WorkState.state.toString != newState) WorkState.sendCommand(newState)
end

Log:

2018-10-16 14:29:15.228 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘Calculate work day’: Couldn’t invoke ‘assignValueTo’ for feature JvmVoid: (eProxyURI: werkweek.rules#|::0.2.0.2.0.0.2.7.0.1.0.0::0::/2)

if(WorkState.state.toString != newState) {
WorkState.sendCommand(newState)
}
You may need the brackets like above.

rule "Calculate work day"
when
   Member of wwDay changed or
   Time cron "0 5 * ? * *" or
   System started
then
   val wwDayFlag = wwDay.members.findFirst[ d | d.name = "wwDay"+now.getDayOfWeek.toString ]
   val newState = if(wwDayFlag.state == ON) "WORK" else "OFF"
    if(WorkState.state.toString != newState) {
       WorkState.sendCommand(newState)
    }
end
   val wwDayFlag = wwDay.members.findFirst[ d | d.name == "wwDay"+now.getDayOfWeek.toString ]

1 Like

Did the trick…