Astro binding season incorrect

There is an open issue. I linked to it in my reply.

Use Time cron triggered rules.

rule "Spring started"
when
    Time cron 0 0 0 1 JUN ? *
then
    // First day of Spring
end
1 Like

The issue has been closed, PR merged some days ago

1 Like

@rlkoshak
I considered that approach but felt it was better to be able to calculate the season at system start no matter when it comes up rather than use persistence which could cernly get mucked up if the exact datetime is missed. It would seem it is not as straight forward to calculate what season we are in right now from date details alone, at least not in OH.

I am considering dropping out to python too get the season. However as it looks like the PR has been merged I will wait. for a much better integrated solution.

Regards

Paul

It’s not hard at all. We have a variable that tells us what date/time it is right now, conveniently enough named now. We have a way to create a variable that we can set to a specific date and time. And we have a way to compare whether a given date/time is before or after another date time.

This is exactly the Time of Day design pattern with the only difference being that it’s working on days of the year instead of times of the day. So just make sure the Rule triggers at the right time and figure out which two start times now is between. The only gotcha is SUMMER which breaks across the new year. But that’s not hard either, just split the test into two.

rule "Calculate the season"
when
    Time cron 0 0 0 1 MAR ? * or
    Time cron 0 0 0 1 JUN ? * or
    Time cron 0 0 0 1 SEP ? * or
    Time cron 0 0 0 1 DEC ? * or
    System started
then
    val firstDayOfFall = new DateTime(now.getYear(), 3, 1, 0, 0)
    val firstDayOfWinter = new DateTime(now.getYear(), 6, 1, 0, 0)
    val firstDayOfSpring = new DateTime(now.getYear(), 9, 1, 0, 0)
    val firstDayOfSummer = new DateTime(now.getYear(), 12, 1, 0, 0)

    var season = "UNKNOWN"
    switch(now){
        case now.isBefore(firstDayOfFall):                                    season = "SUMMER"
        case now.isAfter(firstDayOfFall) && now.isBefore(firstDayOfWinter):   season = "FALL"
        case now.isAfter(firstDayOfWinter) && now.isBefore(FirstDayOfSpring): season = "WINTER"
        case now.isAfter(firstDayOfSpring) && now.isBefore(FirstDayOfSummer): season = "SPRING"
        case now.isAfter(firstDayOfSummer):                                   season = "SUMMER"
    }

    Season.postUpdate(season)
end

When you look for similar approaches in Python, you will see it’s exactly the same approach. For example date - Determine season given timestamp in Python using datetime - Stack Overflow.

Thank you for your input RIch.

I have two potential options now, wait for the binding update or self serve using the rule examples provided.

Thanks
Paul

Or both, use the Rules until the binding update makes it way to you. Rules don’t have to be permanent. :smiley:

I think your right :grin: I just did not want to commit myself, I have a week of in a few days so could easily fit it in. I will update the final rule used here for anyone else to try.

Cheers
Paul

I decided there is no time like the present to delve straight in and get the rule up and running. then I hit a snag


I have added commenting and corrected a slip but essentially its the same rule as the example provided. I have declared the item Season so it exists as a String.
If I comment out the WINTER line (the current season) then the code runs through but when the WINTER line is uncommented it fails, see log entry below.

LOG

2020-06-20 09:29:42.374 [INFO ] [e.smarthome.model.script.calc-season] - Autumn:2020-03-01T00:00:00.000+13:00

2020-06-20 09:29:42.386 [INFO ] [e.smarthome.model.script.calc-season] - Winter:2020-06-01T00:00:00.000+12:00

2020-06-20 09:29:42.389 [INFO ] [e.smarthome.model.script.calc-season] - Spring:2020-09-01T00:00:00.000+12:00

2020-06-20 09:29:42.399 [INFO ] [e.smarthome.model.script.calc-season] - Summer:2020-12-01T00:00:00.000+13:00

2020-06-20 09:29:42.400 [INFO ] [e.smarthome.model.script.calc-season] - pre-season:UNKNOWN

2020-06-20 09:29:42.403 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Calculate the season': The name 'FirstDayOfSpring' cannot be resolved to an item or type; line 84, column 60, length 16

The rule as I have it is below:

rule "Calculate the season"
when
    //Time cron 0 0 0 1 MAR ? * or
    //Time cron 0 0 0 1 JUN ? * or
    //Time cron 0 0 0 1 SEP ? * or
    //Time cron 0 0 0 1 DEC ? * or
    System started or
	Item Test received command ON
then
    val firstDayOfFall = new DateTime(now.getYear(), 3, 1, 0, 0)
	logInfo("calc-season","Autumn:"+firstDayOfFall)
    val firstDayOfWinter = new DateTime(now.getYear(), 6, 1, 0, 0)
	logInfo("calc-season","Winter:"+firstDayOfWinter)
    val firstDayOfSpring = new DateTime(now.getYear(), 9, 1, 0, 0)
	logInfo("calc-season","Spring:"+firstDayOfSpring)
    val firstDayOfSummer = new DateTime(now.getYear(), 12, 1, 0, 0)
	logInfo("calc-season","Summer:"+firstDayOfSummer)

    var season = "UNKNOWN"
	logInfo("calc-season","pre-season:"+season)
    switch(now){
        case now.isBefore(firstDayOfFall):                                    season = "SUMMER"
        case now.isAfter(firstDayOfFall) && now.isBefore(firstDayOfWinter):   season = "AUTUMN"
        case now.isAfter(firstDayOfWinter) && now.isBefore(FirstDayOfSpring): season = "WINTER"
        case now.isAfter(firstDayOfSpring) && now.isBefore(FirstDayOfSummer): season = "SPRING"
        case now.isAfter(firstDayOfSummer):                                   season = "SUMMER"
    }

    Season.postUpdate(season)
	logInfo("calc-season","Current Season:"+Season.state)
end

Note: There was a separate error thrown for the CRON triggers so while testing I commented them out to move past them and load the rule.

Regards

Paul

FirstDayOfSpring

It should be firstDayOfSpring in the switch statement (lowercase f). You’ll see an error for the line right after that for FirstDayOfSummer which should be firstDayOfSummer also.

2 Likes

Thanks Rich,
This morning having seen no email of any thread updates I decided to take another look at the errors I had seen yesterday. I found that the time triggered errors could be quietened (not tested) by using quotes. I then found the capitalisation errors you had kindly informed me of in the last message Rich.

I am going to be using this and also using it as an example of rules that trigger for specific days too.

here is the final rule that looks to be working although the cron triggers have yet to be tested.

rule "Calculate the season"
when
    Time cron "0 0 0 1 MAR ? *" or
    Time cron "0 0 0 1 JUN ? *" or
    Time cron "0 0 0 1 SEP ? *" or
    Time cron "0 0 0 1 DEC ? *" or
    System started
then
    val firstDayOfFall = new DateTime(now.getYear(), 3, 1, 0, 0)
    val firstDayOfWinter = new DateTime(now.getYear(), 6, 1, 0, 0)
    val firstDayOfSpring = new DateTime(now.getYear(), 9, 1, 0, 0)
    val firstDayOfSummer = new DateTime(now.getYear(), 12, 1, 0, 0)

    var season = "UNKNOWN"
    switch(now){
        case now.isBefore(firstDayOfFall):                                    season = "SUMMER"
        case now.isAfter(firstDayOfFall) && now.isBefore(firstDayOfWinter):   season = "AUTUMN"
        case now.isAfter(firstDayOfWinter) && now.isBefore(firstDayOfSpring): season = "WINTER"
        case now.isAfter(firstDayOfSpring) && now.isBefore(firstDayOfSummer): season = "SPRING"
        case now.isAfter(firstDayOfSummer):                                   season = "SUMMER"
    }
    Season.postUpdate(season)
	logInfo("calc-season","Current Season:"+Season.state)
end

Thanks Rich for your invaluable assistance.

Regards
Paul

1 Like

Another alternative for this would be to use Ephermeris