Much better to use:
DateTime IssPass "Next ISS Pass [%1$tH:%1$tM:%1tS %1td-%1$tm]" <iss>
Why go out of your way to build a String when you can keep it as a date and then be able to use it as such in your Rules without needing to parse the String back to a DateTime object of some sort? At a minimum it lets us do in one line what took four lines of code using SimpleDateFormat.
The label above lets you format the DateTime like you want. In this case it formats it the same as you defined in your Rule. It uses the Java String Formatter syntax
Here is the Rule:
rule "Parse ISS Epoch"
when
System started or // why?
Item IssPass_Epoch changed
then
IssPass.postUpdate(new DateTime((IssPass_Epoch.state as Number).longValue).toString)
end
What this does is take the Number stored in IssPass_Epoch and converts it to a primitive long (which is what DateTime requires) then uses the toString to get an ISO 8601 formatted date time string that the openHAB DateTimeType knows how to parse.
OK, next is why poll? You already recognize this may not be the best approach. This is what Timers are great for.
You can modify the above Rule to:
val Timer issTimer =null
rule "Process ISS Time"
when
System started or // in this case we need this
Item IssPass_Epoch changed
then
val issPassTime = new DateTime(Long::parse:Long(IssPass_Epoch.state.toString))
IssPass.postUpdate(issPassTime.toString)
issTimer?.cancel // the ? skips this line is issTimer is null
issTimer = createTimer(issPassTime.minusHours(1), [ |
sendNotification("mat@randomemail.co.uk", "ISS Pass at " + IssPass.state.toString)
issTimer = null
])
end
This will set the IssPass Item with the date time of the pass and creates a timer to send you a notification one hour before the received time.
You can use the [Deprecated] Design Pattern: Time Of Day and use something like:
val Timer issTimer =null
rule "Process ISS Time"
when
System started or // in this case we need this
Item IssPass changed
then
val issPassTime = new DateTime(IssPass.state.toString)
issTimer?.cancel // the ? skips this line is issTimer is null
issTimer = createTimer(issPassTime.minusHours(1), [ |
if(vTimeOfDay.state == "NIGHT") sendNotification("mat@randomemail.co.uk", "ISS Pass at " + IssPass.state.toString)
issTimer = null
])
end
In this case the Timer will fire one hour before the ISS is going to pass but only if it is currently NIGHT. We can get a little smarter and use something like the following, assuming the same Items from the Time of Day DP:
val Timer issTimer =null
rule "Process ISS Time"
when
System started or // in this case we need this
Item IssPass changed
then
// Astro calculates the sunrise and sunset times for the current day a few seconds after midnight
// so the naive approach of check if the current time is between sunset and sunrise won't work because
// both values are for today.
val issPassTime = new DateTime(IssPass.state.toString) // when the ISS will pass
val sunset = new DateTime(vSunset_Time.state.toString) // sunset today
val sunrise = new DateTime(vSunrise_Time.state.toString) // sunrise today
// Skip setting the Timer if the ISS pass time will be during the day
if(issPassTime.isAfter(sunrise) && issPassTime.isBefore(sunset)) return; // day time today
if(issPassTime.isAfter(sunrise.plusDays(1)) return; // day time tomorrow, sunrise from today won't be too different from sunrise tomorrow
issTimer?.cancel // the ? skips this line is issTimer is null
issTimer = createTimer(issPassTime.minusHours(1), [ |
sendNotification("mat@randomemail.co.uk", "ISS Pass at " + IssPass.state.toString)
issTimer = null
])
end
I just typed in the code above. It might not be completely typo free.