[SOLVED] Daytimes rule not working

I’m on Debian Stretch with Openhab 2.5 running…

I’m trying to get daytime states with my rule but I can’t figure out why it’s not working.

My rule is based on the Time Of Day Design Pattern from rikoshak

rule "Calculate time of day state" 
when
    System started or 
    Channel 'astro:sun:home:civilDawn#start'  triggered START or
    Channel 'astro:sun:home:civilDawn#end'  triggered START or
    Channel 'astro:sun:home:civilDusk#start'  triggered START or
    Channel 'astro:sun:home:civilDusk#end'  triggered START or
    Time cron "0 1 0 * * ? *" or
    Time cron "0 0 1 * * ? *" or
    Time cron "0 0 10 * * ? *" or
    Time cron "0 0 12 * * ? *"
then
    // logInfo(TimeOfDay, "Calculating time of day...")
  
    val dawn_start = new DateTime(vDawn_Time.state.toString)
    val morning_start = new DateTime(vMorning_Time.state.toString)
    val forenoon_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(14)
    vForenoon_Time.postUpdate(forenoon_start.toString) 
    val noone_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(12)
    vNoon_Time.postUpdate(noone_start.toString)
    val afternoon_start = new DateTime(vAfternoon_Time.state.toString)
    val evening_start = new DateTime(vEvening_Time.state.toString)
    val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(23)
    vNight_Time.postUpdate(night_start.toString)



    // Calculate the current time of day
    var curr = "UNKNOWN"
    switch now {
      case now.isAfter(dawn_start) && now.isBefore(morning_start)       :   curr = "DAWN"
      case now.isAfter(morning_start) && now.isBefore(forenoon_start)   :   curr = "MORNING"      
      case now.isAfter(forenoon_start) && now.isBefore(noone_start)     :   curr = "FORENOON"
      case now.isAfter(noone_start) && now.isBefore(afternoon_start)    :   curr = "NOON"
      case now.isAfter(afternoon_start) && now.isBefore(evening_start)  :   curr = "AFTERNOON"
      case now.isAfter(evening_start) && now.isBefore(night_start)      :   curr = "EVENING"
      case now.isAfter(night_start) && now.isBefore(dawn_start)         :   curr = "NIGHT"
    }

    // Publish the current state
    vTimeOfDay.sendCommand(curr)
end

my corresponding items:

String          vTimeOfDay  	    "aktuelle Tageszeit"
String          vPreviousTimeOfDay  "vorherige Tageszeit"

DateTime        vDawn_Time          "Morgendämmerunmg [%1$tH:%1$tM]"            <sunset>    (gWeather)  { channel="astro:sun:home:civilDawn#start" }
DateTime        vMorning_Time       "Morgen [%1$tH:%1$tM]"                      <sun>       (gWeather)  { channel="astro:sun:home:civilDawn#end" }
DateTime        vForenoon_Time      "Vormittag [%1$tH:%1$tM]"                   <sun>       (gWeather)
DateTime        vNoon_Time          "Mittag [%1$tH:%1$tM]"                      <sun>       (gWeather)
DateTime        vAfternoon_Time     "Nachmittag [%1$tH:%1$tM]"                  <sunset>    (gWeather)  { channel="astro:sun:home:civilDusk#start" }
DateTime        vEvening_Time       "Abend [%1$tH:%1$tM]"                       <sunset>    (gWeather)  { channel="astro:sun:home:civilDusk#end" }
DateTime        vNight_Time         "Nacht [%1$tH:%1$tM]"                       <moon>      (gWeather)

DateTime        vSunrise_Time       "Sonnenaufgang [%1$tH:%1$tM]"               <sun>       (gWeather)  { channel="astro:sun:home:rise#start" }
DateTime        vSunset_Time        "Sonnenuntergang [%1$tH:%1$tM]"             <sunset>    (gWeather)  { channel="astro:sun:home:set#start" }

my astro.thing is working fine - maybe its a DateTime conversion problem while comparing times but I’m geting a bit confused with these conversions…

my log says:
==> /var/log/openhab2/openhab.log <==
2019-01-04 18:50:20.399 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘timeofday.rules’

==> /var/log/openhab2/events.log <==
2019-01-04 18:50:26.038 [ome.event.ItemCommandEvent] - Item 'vTimeOfDay' received command UNKNOWN

I waited 2 days because I read somewhere that sometimes the rule will start working after a uncertain amount of time - but not in my case. Maybe I’m too blind after looking at the code for over 2 days :wink:

Can’t find the error maybe some tips??

Change the switch case from now to true.

var curr = "UNKNOWN"
    switch true {
      case now.isAfter(dawn_start) && now.isBefore(morning_start)     

And change the end of the rule like this.

if (vTimeOfDay.state.toString != curr) {
        vTimeOfDay.sendCommand(curr)
}

Put all together like this:

rule "Calculate time of day state" 
when
    System started or 
    Channel 'astro:sun:home:civilDawn#start'  triggered START or
    Channel 'astro:sun:home:civilDawn#end'  triggered START or
    Channel 'astro:sun:home:civilDusk#start'  triggered START or
    Channel 'astro:sun:home:civilDusk#end'  triggered START or
    Time cron "0 1 0 * * ? *" or
    Time cron "0 0 1 * * ? *" or
    Time cron "0 0 10 * * ? *" or
    Time cron "0 0 12 * * ? *"
then
    // logInfo(TimeOfDay, "Calculating time of day...")
  
    val dawn_start = new DateTime(vDawn_Time.state.toString)
    val morning_start = new DateTime(vMorning_Time.state.toString)
    val forenoon_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(14)
    vForenoon_Time.postUpdate(forenoon_start.toString) 
    val noone_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(12)
    vNoon_Time.postUpdate(noone_start.toString)
    val afternoon_start = new DateTime(vAfternoon_Time.state.toString)
    val evening_start = new DateTime(vEvening_Time.state.toString)
    val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(23)
    vNight_Time.postUpdate(night_start.toString)



    // Calculate the current time of day
    var curr = "UNKNOWN"
    switch true {
      case now.isAfter(dawn_start) && now.isBefore(morning_start)       :   curr = "DAWN"
      case now.isAfter(morning_start) && now.isBefore(forenoon_start)   :   curr = "MORNING"      
      case now.isAfter(forenoon_start) && now.isBefore(noone_start)     :   curr = "FORENOON"
      case now.isAfter(noone_start) && now.isBefore(afternoon_start)    :   curr = "NOON"
      case now.isAfter(afternoon_start) && now.isBefore(evening_start)  :   curr = "AFTERNOON"
      case now.isAfter(evening_start) && now.isBefore(night_start)      :   curr = "EVENING"
      case now.isAfter(night_start) && now.isBefore(dawn_start)         :   curr = "NIGHT"
    }

    // Publish the current state
    if (vTimeOfDay.state.toString != curr) {
        vTimeOfDay.sendCommand(curr)
}
end
1 Like

Hi H102,

hm, I’ve changed the parts you mentioned, but with no luck… I don’t even get a response in my events log that the vTimeOfDay state changed or is changing… any other suggestions??

thanks in advance

cheers,
Dan

Add logging to log out all of the times. I suspect you have gaps or times you expect to be before another are actually after. When that happens none of the conditions in the switch statement are true and you are left with UNKNOWN.

Hi Rich,

I don’t think my cases overlap…

I got:
Dawn at #dawnstart
Morning at #dawnend
Forenoon is at 10:00
Noon is at 12:00
Afternoon is at #duskstart
Evening is at #duskend
Night is at 01:00

I think there is no situation where these times could overlap… but thanks anyway - what I don’t understand is what you mean with gapping times, could this actually happen in my case??

cheers Dan

edit:
I’m in Hamburg/Germany maybe this has something to do with summertime/wintertime switching e.g. GMT+1 + 01:00… just a thought

I’ve got all variables e.g. vDawn_Time, vMorning_Time etc. in my sitemap as text items to see if they’re working - all times are shown correctly!

What did you log to get those tunes? You need to log the vals (e. g. dawn_start) as they are the values being compared.

Check the dates as well. If ASTRO is failing then your ASTRO calculated items will be cut the wrong day.

I haven’t looked that closely at the switch statement but have seen people inadvertently set up a case where there was some time not covered by any of the case statements.

Ahh ok my fault I only had a look at my other variables… I don’t know how to log the state of a variable,

can I use something like:

logInfo(“TimeOfDay”, “The current value is:”+dawn_start.toString" for Dawn Start")

thanks

Dan

yes, that will work too log the variables.

though you are missing a +

logInfo(“TimeOfDay”, “The current value is:”+dawn_start.toString+" for Dawn Start")
1 Like

You’re right… thank you so much for spending your time :wink:

Edit:

Logs:
==> /var/log/openhab2/openhab.log <==
2019-01-04 21:01:35.147 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘timeofday.rules’

==> /var/log/openhab2/events.log <==
2019-01-04 21:01:40.748 [vent.ItemStateChangedEvent] - Date changed from 2019-01-04T21:00:40.742+0100 to 2019-01-04T21:01:40.743+0100
2019-01-04 21:01:40.748 [vent.ItemStateChangedEvent] - DateString changed from 2019-01-04 21:00:40 MEZ to 2019-01-04 21:01:40 MEZ

==> /var/log/openhab2/openhab.log <==
2019-01-04 21:01:40.819 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T07:55:00.000+01:00 for Dawn
2019-01-04 21:01:40.820 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T08:38:00.000+01:00 for Morning
2019-01-04 21:01:40.828 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T16:14:00.000+01:00 for Afternoon
2019-01-04 21:01:40.830 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T16:57:00.000+01:00 for Evening

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

2019-01-04 21:01:40.842 [ome.event.ItemCommandEvent] - Item 'vTimeOfDay' received command UNKNOWN

logging all times:

2019-01-04 21:07:50.792 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'timeofday.rules'
2019-01-04 21:07:56.466 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T07:55:00.000+01:00 for Dawn
2019-01-04 21:07:56.467 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T08:38:00.000+01:00 for Morning
2019-01-04 21:07:56.469 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T10:00:00.000+01:00 for Forenoon
2019-01-04 21:07:56.473 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T12:00:00.000+01:00 for Noon
2019-01-04 21:07:56.476 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T16:14:00.000+01:00 for Afternoon
2019-01-04 21:07:56.478 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T16:57:00.000+01:00 for Evening
2019-01-04 21:07:56.480 [INFO ] [pse.smarthome.model.script.TimeOfDay] - The current value is2019-01-04T01:00:00.000+01:00 for Night

I have no further idea whats going wrong…
Switch case is “UNKNOWN”

I’m on my phone (and down with the flu) so can’t really do the analysis myself. What you need to do is put all of those times in a table, one row for each case statement and see how the times line up.

Are all times covered?
Are there overlaps?
Look at the case conditions, maybe there is a typo?

checked this another time and logged ‘now’… but even this was right. I think I’m going slightly mad on this and should give me a break… :expressionless:

Eddit:
I thought I fixed the problem yestereday, but I test the behavior for another day because I’m not sure if all conditions work to change all daytimes… and post an update here!

have a nice day

Dan

finally its working after adding daystart & dayend, because without it broke my calculation of daytimes… now it looks like that (with little cosmetic changes too :slight_smile: )

rule "Calculate time of day state" 
when
	System started or 
	Channel 'astro:sun:home:civilDawn#event'  triggered START or
	Channel 'astro:sun:home:civilDawn#event'  triggered END or
	Channel 'astro:sun:home:civilDusk#event'  triggered START or
	Channel 'astro:sun:home:civilDusk#event'  triggered END or
	Time cron "0 1 0 * * ? *" or
	Time cron "0 0 1 * * ? *" or
	Time cron "0 0 10 * * ? *" or
	Time cron "0 0 12 * * ? *"
then
	logInfo("TimeOfDay", "Calculating time of day...")
    


	val dawn = new DateTime(vDawn_Time.state.toString)
	val morning = new DateTime(vMorning_Time.state.toString)
	val forenoon = now.withTimeAtStartOfDay.plusDays(1).minusHours(14)
	vForenoon_Time.postUpdate(forenoon.toString)
	val noone = now.withTimeAtStartOfDay.plusDays(1).minusHours(12)
	vNoon_Time.postUpdate(noone.toString)
	val afternoon = new DateTime(vAfternoon_Time.state.toString)
	val evening = new DateTime(vEvening_Time.state.toString)
	val dayend = now.withTimeAtStartOfDay.plusDays(1)
	vDayend_Time.postUpdate(dayend.toString)
	val daystart = now.withTimeAtStartOfDay
	vDaystart_Time.postUpdate(daystart.toString)
	val bedtime = now.withTimeAtStartOfDay.plusDays(1).minusHours(23)
	vBedtime_Time.postUpdate(bedtime.toString)

	// Debug Logging
		/* 
		logInfo("TimeOfDay", "The current value is "+dawn.toString+" for Dawn")
		logInfo("TimeOfDay", "The current value is "+morning.toString+" for Morning")
		logInfo("TimeOfDay", "The current value is "+forenoon.toString+" for Forenoon")
		logInfo("TimeOfDay", "The current value is "+noone.toString+" for Noon")
		logInfo("TimeOfDay", "The current value is "+afternoon.toString+" for Afternoon")
		logInfo("TimeOfDay", "The current value is "+evening.toString+" for Evening")
		logInfo("TimeOfDay", "The current value is "+dayend.toString+" for Dayend")
		logInfo("TimeOfDay", "The current value is "+daystart.toString+" for Daystart")
		logInfo("TimeOfDay", "The current value is "+bedtime.toString+" for Bedtime")
		logInfo("TimeOfDay", "The current value is "+now+" for Now")
		 */

	// Calculate the current time of day
	var curr = "UNKNOWN"
	switch true {
		case now.isAfter(bedtime) && now.isBefore(dawn)			: curr =    "BEDTIME"
		case now.isAfter(dawn) && now.isBefore(morning)         : curr =    "DAWN"
		case now.isAfter(morning) && now.isBefore(forenoon)     : curr =    "MORNING"      
		case now.isAfter(forenoon) && now.isBefore(noone)       : curr =    "FORENOON"
		case now.isAfter(noone) && now.isBefore(afternoon)      : curr =    "NOON"
		case now.isAfter(afternoon) && now.isBefore(evening)    : curr =    "AFTERNOON"
		case now.isAfter(evening)	&& now.isBefore(dayend)		: curr =    "EVENING"
		case now.isAfter(daystart) && now.isBefore(bedtime)		: curr =	"NIGHT"
	}
	// Debug Logging
		logInfo("TimeOfDay", "It's "+curr.toString+" now")

	// Publish the current state
	if (vTimeOfDay.state.toString != curr) {
		vTimeOfDay.sendCommand(curr)
	}
end

and here are the items

String          vTimeOfDay  	    "aktuelle Tageszeit [%s]"

DateTime        vDawn_Time          "Morgendämmerunmg [%1$tH:%1$tM]"            <sunset>    (gWeather)  { channel="astro:sun:home:civilDawn#start" }
DateTime        vMorning_Time       "Morgen [%1$tH:%1$tM]"                      <sun>       (gWeather)  { channel="astro:sun:home:civilDawn#end" }
DateTime        vForenoon_Time      "Vormittag [%1$tH:%1$tM]"                   <sun>       (gWeather)
DateTime        vNoon_Time          "Mittag [%1$tH:%1$tM]"                      <sun>       (gWeather)
DateTime        vAfternoon_Time     "Nachmittag [%1$tH:%1$tM]"                  <sunset>    (gWeather)  { channel="astro:sun:home:civilDusk#start" }
DateTime        vEvening_Time       "Abend [%1$tH:%1$tM]"                       <sunset>    (gWeather)  { channel="astro:sun:home:civilDusk#end" }
DateTime        vDayend_Time        "Tagesende [%1$tH:%1$tM]"                   <moon>      (gWeather)
DateTime        vDaystart_Time      "Tageesstart [%1$tH:%1$tM]"                 <moon>      (gWeather)
DateTime        vBedtime_Time       "Nacht [%1$tH:%1$tM]"                       <moon>      (gWeather)

thanks for all your help - this is the final solution…

Dan