I am not sure, if this has been solved or there is a solution posted somewhere else. In any case, here is my solution for persisting date and time values and restoring them.
Feel free to comment. Before you comment you must know:
a) I am running: openHAB 1.x and
b) I tried for hours with different types and conversions. Nothing worked for me except the solution below.
Some background:
I want openHAB to control my house differently in winter. Therefore, I have a winter mode item that is either ON or OFF. It is turned ON (by code not shown here) when the outside air temperature is less than 5 °C and is turned OFF, when it reaches 15 °C. In addition to the different behaviour of other rules, there is a warning message “frost alarm” sent to our mobiles via Telegram, when the winter mode is turned ON. So I can for example turn off the water for the garden, or I can see, when it is safe to put some plants back on the terrace after the winter.
To be sure, when the winter mode has been changed for the last time, a second item is storing this date and time whenever the winter mode changes from ON to OFF and from OFF to ON (but not for updates, that do not change the value).
As this (date and time type) item cannot be persisted (I am using RRD4J), the last change time was always gone after restarting openHAB. And this is, where we begin:
First of all, we need the items in the .items
file:
Switch Winter_Modus "Wintermodus" { knx="0/0/5" }
DateTime Winter_Modus_last_Change "letzte Änderung [%1$td.%1$tm. %1$tH:%1$tM]"
Number Winter_Modus_last_Change_millis "letzte Änderung [%d]"
Please note that the mode is also synced with my KNX installation and the date does not show the year as I don’t need it (but the data would allow this).
Secondly, we need to make Winter_Modus
and Winter_Modus_last_Change_millis
persistent in rrd4j.persist
:
Strategies
{
everyMinute : "0 * * * * ?"
default = restoreOnStartup
}
Items
{
Winter_Modus : strategy = everyMinute, everyUpdate, restoreOnStartup
Winter_Modus_last_Change_millis : strategy = everyMinute, everyUpdate, restoreOnStartup
}
We can show all values in the .sitemap
, but it does not make sense to show Winter_Modus_last_Change_millis
as it is only used internally for persistence:
Frame label="Wintermodus"
{
Text item=Winter_Modus icon="climate" label="Status [MAP(de.map):%s]" valuecolor=[ON="black"]
Text item=Winter_Modus_last_Change icon="calendar"
// Text item=Winter_Modus_last_Change_millis icon="calendar"
}
And now to the important .rules
part. There are three rules:
The first rule is executed when the winter mode changes to ON. It updates both last change items with the current time and issues the “frost alarm”:
rule "Wintermodus ein und Frostalarm melden"
when
Item Winter_Modus changed to ON
then
Winter_Modus_last_Change.postUpdate (now.toString)
Winter_Modus_last_Change_millis.postUpdate (now.millis)
val String msg = "Frostalarm! Wintermodus eingeschaltet."
sendTelegram ("mobile1", msg)
sendTelegram ("mobile2", msg)
end
The second rule is similar, but executed when the winter mode changes to OFF. It updates both last change items again, but does not telegram an alarm:
rule "Wintermodus aus"
when
Item Winter_Modus changed to OFF
then
Winter_Modus_last_Change.postUpdate (now.toString)
Winter_Modus_last_Change_millis.postUpdate (now.millis)
end
So, now we have the last change time displayed in the sitemap as a string and it is also persisted in the database as a numeric value.
This was pretty easy. But we want the numeric value back into openHAB when it is restarted. To achieve it, we need to convert the numeric value back to a date time string. This is where I was stuck for hours and I came back with this:
import java.text.SimpleDateFormat
import org.joda.time.DateTime
rule "Winter_Modus_last_Change restaurieren"
when
System started
then
if ((Winter_Modus_last_Change.state != Undefined) && (Winter_Modus_last_Change.state != Uninitialized)) return false
var Number millis = Winter_Modus_last_Change_millis.state
if ((millis != Undefined) && (millis != Uninitialized))
{
val SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
val dt = new DateTime(millis.longValue)
val String str = sdf.format(dt.toDate)
Winter_Modus_last_Change.postUpdate (str)
} else logWarn ("Winter_Modus_last_Change restaurieren", "Bug: No millis in DB!")
end
As you can see, the code is only executed, if the date and time string item has ‘no’ value to avoid overwriting data if openHAB is not restarted but the rules have been changed.
After getting the numeric value (restored from the persistence service), it is converted and posted into the date and time string item. If the item has never been persisted, a warning is logged instead.
I hope, I could help @andre or @Denis_Lambert. Let me know, if you could improve my code (or you find it completely useless ).
Best regards,
Stefano