[SOLVED] Time Of Day - Unknown at day change over

Given the following times:

2018-09-23 00:01:51.236 [INFO ] [e.smarthome.model.script.Time of day] - Now: 2018-09-23T00:01:51.233+12:00 Morning Start 2018-09-23T05:00:00.000+12:00 day Start 2018-09-23T08:00:00.000+1
2:00 evening start 2018-09-23T17:18:00.000+12:00 late evening: 2018-09-23T22:00:00.000+12:00 night start 2018-09-23T23:00:00.000+12:00

And the following code:

var newToD = "UNKNOWN"
    switch now {
        case now.isAfter(morningStart) && now.isBefore(dayStart)    : newToD = "MORNING"
        case now.isAfter(dayStart) && now.isBefore(eveningStart)    : newToD = "DAY"
        case now.isAfter(eveningStart) && now.isBefore(lateEvening) : newToD = "EVENING"
        case now.isAfter(lateEvening) && now.isBefore(nightStart)   : newToD = "LATEEVENING"
        case now.isAfter(nightStart)                                : newToD = "NIGHT"

    }

After midnight, the ToD state of UNKNOWN is being set

Any pointers for fixing?

Can you provide the full rule and items please.

Full rule:

rule "Time of Day"
when
    System started or
    Item g_temperature_average received update or
    Time cron "0 0 5 * * ? *" or
    Time cron "0 0 8 * * ? *" or
    Time cron "0 0 16 * * ? *" or
    Time cron "0 0 22 * * ? *"
then
    // get the DateTime for the start of the time periods
    //5am
    val morningStart = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-(heating_morning_time_on.state as Number).intValue)
    //8am
    val dayStart = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-(heating_morning_time_off.state as Number).intValue)
    //4pm
    //val eveningStart = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-16)
    val eveningStart = new DateTime(Evening_Time.state.toString())
    //10pm
    val lateEvening = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-(heating_daytime_time_off.state as Number).intValue)

    val nightStart = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-(lamp_lighting_time_off.state as Number).intValue)
    logInfo("Time of day",String::format("Now: %s Morning Start %s day Start %s evening start %s late evening: %s night start %s",
                    now,morningStart,dayStart,eveningStart,lateEvening,nightStart))

    var newToD = "UNKNOWN"
    switch now {
        case now.isAfter(morningStart) && now.isBefore(dayStart)    : newToD = "MORNING"
        case now.isAfter(dayStart) && now.isBefore(eveningStart)    : newToD = "DAY"
        case now.isAfter(eveningStart) && now.isBefore(lateEvening) : newToD = "EVENING"
        case now.isAfter(lateEvening) && now.isBefore(nightStart)   : newToD = "LATEEVENING"
        case now.isAfter(nightStart)                                : newToD = "NIGHT"

    }

    if(heating_timeofday.state.toString != newToD)
    {
        heating_timeofday.postUpdate(newToD)
        logInfo("Time of day","Setting Time of Day: " + newToD)
    }
end

heating_morning_time_on is 5
heating_morning_time_off is 8
heating_daytime_time_off is 22
lamp_lighting_time_off is 23

For calculating the times.

Hi,
UNKNOWN is your default value which is set when no case statement is met. So your values are:

Now:             2018-09-23T00:01:51.233+12:00 

Morning Start    2018-09-23T05:00:00.000+12:00 
day Start        2018-09-23T08:00:00.000+12:00 
evening start    2018-09-23T17:18:00.000+12:00 
late evening     2018-09-23T22:00:00.000+12:00 
night start      2018-09-23T23:00:00.000+12:00

As you can see, now is earlier than all your other times resulting in all case statements being false.

Cheers,
Dominik

Here is the rule I use for time:

rule "Calculate time of day state"
when
    Time cron "0 * * ? * *" 
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"
    }
//  logInfo("Time_Of_Day", "curr_time=" + curr_time + ", night_start=" + night_start + ", morning_start=" + morning_start
//      + ", day_start=" + day_start + ", evening_start=" + evening_start + ", midnight_time=" + midnight_time
//      + ", new_val=" + new_val)


    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

With the following items:

DateTime    Sun_Dawn_Start      "Dawn [%1$tR]"              <time>      { channel="astro:sun:local:civilDawn#start" }
DateTime    Sun_Dusk_End        "Dusk [%1$tR]"          <time>      { channel="astro:sun:local:civilDusk#end" }
String      Time_Of_Day         "Time of day [%s]"    

Isn’t Now after night?
Now: 2018-09-23T00:01:51.233+12:00
night start 2018-09-23T23:00:00.000+12:100:
Hmm no it’s not because it’s finally switch from 2018-09-22 to 2018-09-23.
So i need another case for isBefore(morningStart) I think. Right?

To get around the wrapping around midnight, you can make your default the ToD that wraps it. So, instead of using “UNKNOWN” for the default, use “NIGHT” and then remove it from the switch/case. IIRC, this is how the DP is written too.

1 Like

Probably work just as well actually. Sometimes the most obvious things are right in front of your face

1 Like

My brain fired this one off in the background… IMO it is less elegant, but think it should work…

case now.isAfter(nightStart) && now.isBefore(now.plusDays(1).withTimeAtStartOfDay)                               : newToD = "NIGHT"
case now.isAfter(now.withTimeAtStartOfDay) && now.isBefore(morningStart)                               : newToD = "NIGHT"