Skip to content
This repository has been archived by the owner on May 17, 2021. It is now read-only.

Enhacements to 'time' expression in rules #633

Closed
openhab-bot opened this issue Dec 10, 2013 · 8 comments
Closed

Enhacements to 'time' expression in rules #633

openhab-bot opened this issue Dec 10, 2013 · 8 comments

Comments

@openhab-bot
Copy link
Collaborator

  1. The existing time expression should be enhanced to support more "well-known" times and simple math. Right now there are only 2 well known times: Time is midnight and Time is noon. There should be sunrise and sunset times too. They can be calculated based on coordinates of location. Coordinates should be specified in openhab.cfg. There are existing java codes for that on the net. This valuation should support simple math like sunrise+30m or sunset-1h.
  2. Example Use Case is switching on and off lights based on sunrise and sunset times, it is also usefull for irrigation, shades, a lot of other hings. User installation can lack light sensor and this can be fixed by sunset and sunrise times. Simple math is needed so that you can switch lights before it becomes dark and switch them off after it is sunny enough.

Original issue: http://code.google.com/p/openhab/issues/detail?id=71

@openhab-bot
Copy link
Collaborator Author

this lib looks promising http://www.jstott.me.uk/jsuntimes/

@openhab-bot
Copy link
Collaborator Author

I use these fields in Misterhouse, would welcome them in Openhab:
$Time_Sunset_Twilight,
$Time_Sunrise_Twilight,
$Dark: true between $Time_Sunset_Twilight and $Time_Sunrise_Twilight, false otherwise.
These are more relevant than fixed offsets before sunrise and after sunset.

@openhab-bot
Copy link
Collaborator Author

This can be achieved by using the following (thanks RaK for providing the base script)

#################################################
import org.openhab.core.library.types.*
import java.lang.Math

// constants
var Number K = 0.017453

// coordinates (see Google-Maps)
var Number latitude = xx.xxxxxx
var Number longitude = xx.xxxxxx

rule "Calculate Sunheight and Azimut"
when
Time cron "0 0/5 * * * ?"
then
var Number tageszahl
var Number deklination
var Number zeitgleichung
var Number stundenwinkel
var Number x
var Number y
var Number sonnenhoehe
var Number azimut

var month  = now.getMonthOfYear
var day    = now.getDayOfMonth
var hour   = now.getHourOfDay
var minute = now.getMinuteOfHour

// Source: http://www.jgiesen.de/SME/tk/index.htm
tageszahl = (month - 1) * 30 + day + hour / 24 
deklination = -23.45 * Math::cos((K * 360 * (tageszahl + 10) / 365).doubleValue)
zeitgleichung = 60.0 * (-0.171 * Math::sin((0.0337*tageszahl+0.465).doubleValue) - 0.1299 * Math::sin((0.01787*tageszahl-0.168).doubleValue))
stundenwinkel = 15.0 * (hour.doubleValue + (minute.doubleValue/60.0) - (15.0-longitude)/15.0 - 12.0 + zeitgleichung/60.0)
x = Math::sin((K * latitude).doubleValue()) * Math::sin((K * deklination).doubleValue()) + Math::cos((K * latitude).doubleValue()) * Math::cos((K * deklination).doubleValue()) * Math::cos((K * stundenwinkel).doubleValue())
y = - (Math::sin((K*latitude).doubleValue) * x - Math::sin((K*deklination).doubleValue)) / (Math::cos((K*latitude).doubleValue) * Math::sin(Math::acos(x.doubleValue)))
sonnenhoehe = Math::asin(x.doubleValue) / K

var break = hour.doubleValue + (minute.doubleValue/60.0) <= 12.0 + (15.0-longitude)/15.0 - zeitgleichung/60.0 
if (break) {
    azimut = Math::acos(y.doubleValue) / K
} else {
    azimut = 360.0 - Math::acos(y.doubleValue) / K
}

logDebug("Sun.rules", "Calculated new SunHeight angle '" + sonnenhoehe + "°'")
logDebug("Sun.rules", "Calculated new Azimut angle '" + azimut + "°'")

// post new values to the bus
Sun_Height.postUpdate(sonnenhoehe)
Sun_Azimut.postUpdate(azimut)

end

#################################################

furthermore you need two new items of type 'Number'

  • Sun_Height
  • Sun_Azimut

In order to react properly please add other rules with an Item-Changed-Trigger in Sun_Height or Sun_Azimut which in turn can do all the time tweaks using joda-time

Does that suite your needs?

@openhab-bot
Copy link
Collaborator Author

may be this will also help:

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*

import java.lang.Math
import java.util.Date
import java.util.Calendar
import org.joda.time.DateTime

// Change this reflecting your destination
var Number lat = x.xxxx
var Number lng = y.yyyy

var Calendar sunrise = Calendar::getInstance()
var Calendar sunset = Calendar::getInstance()

rule "Sun"
when
Time cron "0 0/30 * * * ?"
then
// http://www.suncalc.net
var J1970 = 2440588
var J2000 = 2451545
var deg2rad = Math::PI / 180
var M0 = 357.5291 * deg2rad
var M1 = 0.98560028 * deg2rad
var J0 = 0.0009
var J1 = 0.0053
var J2 = -0.0069
var C1 = 1.9148 * deg2rad
var C2 = 0.0200 * deg2rad
var C3 = 0.0003 * deg2rad
var P = 102.9372 * deg2rad
var e = 23.45 * deg2rad
var th0 = 280.1600 * deg2rad
var th1 = 360.9856235 * deg2rad
var h0 = -0.83 * deg2rad //sunset angle
var d0 = 0.53 * deg2rad //sun diameter
var h1 = -6 * deg2rad //nautical twilight angle
var h2 = -12 * deg2rad //astronomical twilight angle
var h3 = -18 * deg2rad //darkness angle
var msInDay = 1000 * 60 * 60 * 24
var lw = -lng * deg2rad
var phi = lat * deg2rad

var datum = new Date()

var J = datum.getTime() / msInDay - 0.5 + J1970
var n = Math::round( (J - J2000 - J0 - lw/(2 * Math::PI)).doubleValue)
var Js = (J2000 + J0 + (0 + lw)/(2 * Math::PI) + n)
var M = ( M0 + M1 * (Js - J2000))
var C = C1 * Math::sin(M.doubleValue) + C2 * Math::sin((2 * M).doubleValue) + C3 * Math::sin((3 * M).doubleValue)
var Lsun = M + P + C + Math::PI
var Jtransit = Js + (J1 * Math::sin(M.doubleValue)) + (J2 * Math::sin((2 * Lsun).doubleValue))
var d = Math::asin((Math::sin(Lsun.doubleValue) * Math::sin(e.doubleValue)).doubleValue)
var w0 = Math::acos(((Math::sin(h0.doubleValue) - Math::sin(phi.doubleValue) * Math::sin(d.doubleValue)) / (Math::cos(phi.doubleValue) * Math::cos(d.doubleValue))).doubleValue)
var w1 = Math::acos(((Math::sin((h0+d0).doubleValue) - Math::sin(phi.doubleValue) * Math::sin(d.doubleValue)) / (Math::cos(phi.doubleValue) * Math::cos(d.doubleValue))).doubleValue)

var Jset            = J2000 + J0 + (w0 + lw)/(2 * Math::PI) + n + (J1 * Math::sin(M.doubleValue)) + (J2 * Math::sin((2 * Lsun).doubleValue))
var Jsetstart       = J2000 + J0 + (w1 + lw)/(2 * Math::PI) + n + (J1 * Math::sin(M.doubleValue)) + (J2 * Math::sin((2 * Lsun).doubleValue))

var Jrise           = Jtransit - (Jset - Jtransit)
var Jriseend        = Jtransit - (Jsetstart - Jtransit)

var sunrise_ms_start = ( (Jrise + 0.5 - J1970) * msInDay).longValue
var sunrise_ms_end   = ( (Jriseend + 0.5 - J1970) * msInDay).longValue
var sunset_ms_start  = ((Jsetstart + 0.5 - J1970) * msInDay).longValue
var sunset_ms_end    = ((Jset + 0.5 - J1970) * msInDay).longValue

// Items:
// DateTime        SunRise "Sonnenaufgang [%1$tA, %1$td.%1$tm.%1$tY %1$tT]"                <calendar>
// DateTime        SunSet  "Sonnenuntergang [%1$tA, %1$td.%1$tm.%1$tY %1$tT]"         <calendar>

var Calendar sunrise_start = Calendar::getInstance()
sunrise_start.setTimeInMillis( sunrise_ms_start )
SunRise.postUpdate( new DateTimeType(sunrise_start))

var  Calendar sunset_start = Calendar::getInstance()
sunset_start.setTimeInMillis( sunset_ms_start )
SunSet.postUpdate( new DateTimeType(sunset_start))

end

@openhab-bot
Copy link
Collaborator Author

Can someon confirm that comment #4 give valid results? I tried it for my self (northern germany) and got

SunRise 3:44 seems to be wrong
SunSet 15:16 seens to be UTC, so this is correct

while Google gives me

SunRise 8:34 local
SunSet 16:17 local

@openhab-bot
Copy link
Collaborator Author

This code works for me :
import org.openhab.core.library.types.*
import java.lang.Math

// Constants
var Number K = 0.017453

// Change this reflecting your destination
var Number latitude = 50.892
var Number longitude = 4.733

rule "Set Sun and Dawn States"
when
Time cron "0 0/5 * * * ?"
then
var Number tageszahl
var Number deklination
var Number zeitgleichung
var Number stundenwinkel
var Number x
var Number y
var Number sonnenhoehe
var Number azimut

var month  = now.getMonthOfYear
var day    = now.getDayOfMonth
var hour   = now.getHourOfDay
var minute = now.getMinuteOfHour

// Source: http://www.jgiesen.de/SME/tk/index.htm
tageszahl = (month - 1) * 30 + day + hour / 24 
deklination = -23.45 * Math::cos((K * 360 * (tageszahl + 10) / 365).doubleValue)
zeitgleichung = 60.0 * (-0.171 * Math::sin((0.0337*tageszahl+0.465).doubleValue) - 0.1299 * Math::sin((0.01787*tageszahl-0.168).doubleValue))
stundenwinkel = 15.0 * (hour.doubleValue + (minute.doubleValue/60.0) - (15.0-longitude)/15.0 - 12.0 + zeitgleichung/60.0)
x = Math::sin((K * latitude).doubleValue()) * Math::sin((K * deklination).doubleValue()) + Math::cos((K * latitude).doubleValue()) * Math::cos((K * deklination).doubleValue()) * Math::cos((K * st

undenwinkel).doubleValue())
y = - (Math::sin((K_latitude).doubleValue) * x - Math::sin((K_deklination).doubleValue)) / (Math::cos((K*latitude).doubleValue) * Math::sin(Math::acos(x.doubleValue)))
sonnenhoehe = Math::asin(x.doubleValue) / K

var break = hour.doubleValue + (minute.doubleValue/60.0) <= 12.0 + (15.0-longitude)/15.0 - zeitgleichung/60.0 
if (break) {
    azimut = Math::acos(y.doubleValue) / K
} else {
    azimut = 360.0 - Math::acos(y.doubleValue) / K
}

logDebug("Sun.rules", "month: " + month)
logDebug("Sun.rules", "day: " + day)
logDebug("Sun.rules", "hour: " + hour)
logDebug("Sun.rules", "minute: " + minute)
logDebug("Sun.rules", "tageszahl: " + tageszahl)
logDebug("Sun.rules", "deklination: " + deklination)
logDebug("Sun.rules", "zeitgleichung: " + zeitgleichung)
logDebug("Sun.rules", "stundenwinkel: " + stundenwinkel)
logDebug("Sun.rules", "x: " + x)
logDebug("Sun.rules", "y: " + y)
logDebug("Sun.rules", "sonnenhoehe: " + sonnenhoehe)
logDebug("Sun.rules", "azimut: " + azimut)

logDebug("Sun.rules", "Calculated new SunHeight angle '" + sonnenhoehe + "°'")
logDebug("Sun.rules", "Calculated new Azimut angle '" + sonnenhoehe + "°'")

// Send all calculations to the event bus

Sun_Height.postUpdate(sonnenhoehe)
Sun_Azimut.postUpdate(azimut)
Daytime.postUpdate( if (sonnenhoehe > 0) OPEN else CLOSED )
if (hour > 3 && hour < 10){
Sun_Dawn_Civil.postUpdate( if (sonnenhoehe > -6 && sonnenhoehe < 0 ) OPEN else CLOSED )
Sun_Dawn_Nautical.postUpdate( if (sonnenhoehe > -12 && sonnenhoehe < -6 ) OPEN else CLOSED )
Sun_Dawn_Astronomical.postUpdate( if (sonnenhoehe > -18 && sonnenhoehe < -12) OPEN else CLOSED )
} if (hour > 15 && hour < 21) {
Sun_Dusk_Civil.postUpdate( if (sonnenhoehe > -6 && sonnenhoehe < 0 ) OPEN else CLOSED )
Sun_Dusk_Nautical.postUpdate( if (sonnenhoehe > -12 && sonnenhoehe < -6 ) OPEN else CLOSED )
Sun_Dusk_Astronomical.postUpdate( if (sonnenhoehe > -18 && sonnenhoehe < -12) OPEN else CLOSED )
}

end

in items
Contact Sun_Dawn_Civil "Zon dawn civil [MAP(sunstates.map):%S]" (Sun)
Contact Sun_Dawn_Nautical "Zon dawn nautical [MAP(sunstates.map):%S]" (Sun)
Contact Sun_Dawn_Astronomical "Zon dawn astronomical [MAP(sunstates.map):%S]" (Sun)
Contact Sun_Dusk_Civil "Zon dusk civil [MAP(sunstates.map):%S]" (Sun)
Contact Sun_Dusk_Nautical "Zon dusk nautical [MAP(sunstates.map):%S]" (Sun)
Contact Sun_Dusk_Astronomical "Zon dusk astronomical [MAP(sunstates.map):%S]" (Sun)
Contact Daytime "Daytime [MAP(test.map):%s]" (Sun)

Maybe this helps.
Regards,
Nico

@openhab-bot
Copy link
Collaborator Author

#7 gzockoll
Shame on me ... i mixed up the variables "lng" and "lat". :(

Apr 2, 2013 Delete comment #8 kristian.backstrom
It seems to me, that #4 gives good results for sunrise / sunset.

It also seems to me that #6 gives me negative sun height values quite too early in the evenings. My coordinates are roughly 25,66E and 60,39N (if you like to test).

Have anyone written a rule for calculating the solar beam hitting angle against flat solar collectors for a given time? The additional parameters would naturally be panel tilt angle and panel rotation angle.

I would like to forecast their power, by also using weather forecasts for estimating the cloud cover.

Regards,
Kristian

Apr 3, 2013 Delete comment Project Member #9 teichsta
good question ...

I would propose to ask the question on the google group since there are more observers than on this issue.

Regards,

Thomas E.-E.

Jun 28, 2013 Delete comment #11 Erland.Lestander
For sake of completness, two booleans should be made available as well:
MidnightSun and MidWinterDarkness, or something similiar in name.
Those should indicate when we are outside of the valid region for the equation, i.e. when the sun doesn't set resp. rise. Then the equation work for everybody (on this planet).

Jul 17, 2013 Delete comment #12 evazzoler
Why not integrate this into the official code with the next release?

Jul 18, 2013 Delete comment Project Member #13 teichsta
we could add the calculation rule to the demo package, yes

Jul 24, 2013 Delete comment #14 [email protected]
No, I meant in the code giving the possibility to use a short syntax in a rule:

"Time is sunset"
or
"Time is sunrise.plusHours(2)"

Pay attention on this: there is no home automation where no astronomical timer is provided...

Jul 24, 2013 Delete comment Project Member #15 belovictor
I would agree with that, those functions should be nicely available.

Jul 25, 2013 Delete comment Project Member #16 kai.openhab
sounds like a good idea, yes.

Sep 15, 2013 Delete comment #17 [email protected]
This is something that I needed for my own Apache Karaf project. I'm in the process of converting it from Apache Karaf to OpenHab but will have difficulty converting the sunrise/sunset functionality as OpenHab is quite restricted regarding extension of the trigger mechanism.
This component really should allow an extensible mechanism of allowing custom triggers to be written and deployed as bundles.
In the meantime I will try to package up my Quartz Astrological Scheduler and make it available. As OpenHab uses Quartz it would fit straight in if the createTimer method was changed to switch schedulers instead of statically using the cron scheduler.

Sep 16, 2013 Delete comment Project Member #18 kai.openhab
For the Eclipse SmartHome project, I plan to further modularize the rule engine - triggers as addons definitely sound like a good idea.

@teichsta
Copy link
Member

meanwhile the Astro-Binding (see https://github.com/openhab/openhab/wiki/Astro-binding) has been implemented which should solve the problem

hubermi pushed a commit to hubermi/openhab that referenced this issue Jan 10, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants