I’ve just added a rule that allows OpenHAB uptime to be displayed in a human readable format, and also reboot the system in the middle of the night once it has been up for over 7 days. As I’m doing a lot of work on the system I’ve steered away from a simple cron style reboot, and intend extending the time between reboots once I know how long it can go before it has problems. Before updating to OH2 it needed to reboot twice a week to prevent the user interface from throwing can’t read sitemap type errors, after about 6 days, and usually at an inconvenient time. I decided not to use the system info binding to save on clock cycles
Items:
String OHStartedAt
String OHFriendlyUptime
sitemap:
Text item=OHFriendlyUptime label="System Uptime [%s]" icon="clock"
rules:
var Long Uptime
val Boolean RebootDue = false
rule "Calculate Uptime"
when Time cron "0 * * * * ?" then
if (OHStartedAt.state == NULL)
{ var DateTime StartedTime = (now)
OHStartedAt.sendCommand(StartedTime.toString)
logInfo("Testing", "OHStartedAt " +OHStartedAt.state)
} else {
var DateTime BegunAt = parse(OHStartedAt.state.toString)
Uptime = (now.getMillis() - BegunAt.getMillis())/60000
// logInfo("Testing", "Uptime in minutes is " +Uptime)
if (Uptime > 10080) { RebootDue = true }
var String UT
var days = Uptime/1440
Uptime = Uptime - days*1440
var hour = Uptime/60
Uptime = Uptime - hour*60
var min = Uptime
UT = days+ "d "+ hour + "h "+ min + "m"
OHFriendlyUptime.sendCommand(UT)
}
end
rule "Reboot downstairs to prevent it getting snotty"
when Time cron "0 50 3 * * ?" then if (RebootDue) { executeCommandLine('"sudo" "reboot"', 5000) }
end
The above rule works on OH2.0, to get the rule to run on OH 1.8 change the line
I am curious how you would (automatically) retrieve the uptime of the openHAB (java) process, since the SystemInfo binding does not let you determine a process id. The SystemInfo binding does give you the computer uptime, however.
For my purposes (display only, no scheduled reboots) I have both the computer uptime through the SystemInfo binding and the uptime of the openHAB process (usually shorter, since I tend to restart the openhab2.service every now and then) through the Exec binding.
// computes nicely formatted duration from given minutes
(function(i){
// seconds to minutes
i = Math.floor(i / 60)
var d = Math.floor(i / (24 * 60));
var h = Math.floor((i / 60) - (24 * d));
var m = Math.round(i - 60 * (24 * d + h));
var result = '';
// days
if (d > 0) {
result = result + d;
if (d == 1) {
result = d + ' day';
} else {
result = d + ' days';
}
}
// hours
if (h > 0) {
if (result != '') {
result = result + ', ';
}
result = result + h;
if (h == 1) {
result = result + ' hour';
} else {
result = result + ' hours';
}
}
// minutes
if (m > 0) {
if (result != '') {
result = result + ', ';
}
result = result + m;
if (m == 1) {
result = result + ' minute';
} else {
result = result + ' minutes';
}
}
return result;
})(input)
demo.items
// Number type does not yet work for exec binding
String System_openHAB_Uptime "openHAB uptime [JS(duration_seconds.js):%s]" <clock> (System) { channel="exec:command:uptime:output" }
The rule sets an item - OHStartedAt- at startup with the current time, and then once this is set, every minute it subtracts that from the current time to give the uptime. As I always reboot the whole system rather than restarting the service it gives me an approximate runtime.
There are of course several other ways to do this, and as I couldn’t find one I wrote my own and posted it.
Nice alternative way - I have yet to tame the new exec binding so everything I do is via a rule so far.
Seems to be working great! Only set up today so haven’t had the the system restart yet, I’ll wait to see how that performs. But other than that I love the new formatted appearance of Uptime
This is working great for me, too!
The only addonI have is the comment above - it computes duration from given seconds…
The script is nearly the same as for the uptime in the systeminfo binding (Community post) (provided also by Robert)- but only nearly:
The systeminfo binding script really calculates system uptime from given minutes (provided by the binding).
It is missing the
// seconds to minutes
i = Math.floor(i / 60)
So you have to use a different script for openhab runtime than for system runtime.
Maybe that helps others not to stumble into the same problem as me…
.
When using the 4 files from Robert I get the message :
2017-09-10 21:51:02.554 [WARN ] [.core.transform.TransformationHelper] - Cannot get service reference for transformation service of type REGEX
2017-09-10 21:51:02.555 [WARN ] [hab.binding.exec.handler.ExecHandler] - Couldn’t transform response because transformationService of type ‘REGEX’ is unavailable
Thanks for this, nice and simple. Although your cron format is wrong. Unsure what time of the day 50 o’clock is
...cron "0 50 3 * * ?"...
I also get this when saving the rules file. Still seems to work though.
2018-01-31 11:16:44.982 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model ‘home.rules’, using it anyway:
Assignment to final field
Constant condition is always false.
I had this rule by @kevin and it was working great until I added dbmap Persistence and now on every reboot the system maintains the original “OHStartedAt” value…there for I would get in to a constant reboot scenario if I hadnt commented out the final part of the rule that does the reboot… Anyone know why or how to reset the “OHStartedAt” value on a reboot?
My version of the Rule is here:
var Long Uptime
var Boolean RebootDue = false
rule "Calculate Uptime"
when Time cron "0 * * * * ?" then
if (OHStartedAt.state == NULL)
{ var DateTime StartedTime = (now)
OHStartedAt.sendCommand(StartedTime.toString)
logInfo("Testing", "OHStartedAt " +OHStartedAt.state)
}
else
{
var DateTime BegunAt = parse(OHStartedAt.state.toString)
Uptime = (now.getMillis() - BegunAt.getMillis())/60000
// logInfo("Testing", "Uptime in minutes is " +Uptime)
if (Uptime > 10080) { RebootDue = true }
var String UT
var days = Uptime/1440
Uptime = Uptime - days*1440
var hour = Uptime/60
Uptime = Uptime - hour*60
var min = Uptime
UT = days+ "d "+ hour + "h "+ min + "m"
OHFriendlyUptime.sendCommand(UT)
}
logInfo("Is a Reboot Due?", "RebootDue Status Flag = " +RebootDue)
logInfo("OHStartedAt", "Last Rebooted on " +OHStartedAt.state)
end
// rule "Reboot PiServer"
// when RebootDue = true
// then executeCommandLine("sudo /sbin/reboot", 60000)
// end
I added in false (gGroups) after each of the string and other items that did not have them previously but this did not change anything and after a reboot the OHStartedAt string still persisted.
I have been playing with additional rule entry to reset the String each restart…that appears to be working and I will monitor the output for a week to see if it works longer term.
rule "Reset Clock"
when
System started
then
{ var DateTime StartedTime = (now)
OHStartedAt.sendCommand(StartedTime.toString)
logInfo("Testing", "OHStartedAt " +OHStartedAt.state)
}
end
I would still like to know how to over ride the dbmap persistence on those items not requiring that, as I had done it for another default.items and that works OK:
I’m using the persistence groups as kind of tags for items. Every item that gets persisted, is in the gPersist group. Every item which should be restored on startup is in gRestoreOnStartup. I do not use gLights or gPower in persistence, a persisted lights item is in both groups.
I would like to share my setup for tracking uptime, adapted from the posts here and extended using java specific functionality.
I am using the following for tracking PC uptime (“CPU uptime”) and openHAB uptime. The solution uses java’s ManagementFactory to access the uptime of the openHAB java process, and systeminfo addon to access PC uptime (“cpu uptime”). The rules are setup such that they do not rely on persistence, and the values are restored even if items are re-created, e.g. when modifying the items file.
import java.lang.management.ManagementFactory
import java.time.ZonedDateTime
import java.time.Instant
import java.time.ZoneOffset
val formatDurationToText = [ Number millis |
// http://stackoverflow.com/questions/13018550/time-since-ago-library-for-android-java
val Number SECOND_MILLIS = 1000;
val Number MINUTE_MILLIS = 60 * SECOND_MILLIS;
val Number HOUR_MILLIS = 60 * MINUTE_MILLIS;
val Number DAY_MILLIS = 24 * HOUR_MILLIS;
var String tmp;
if (millis < MINUTE_MILLIS) {
tmp = "less than a minute";
} else if (millis < 2 * MINUTE_MILLIS) {
tmp = "couple of minutes";
} else if (millis < 50 * MINUTE_MILLIS) {
tmp = String::format("%.2f", millis / MINUTE_MILLIS) + " minutes";
} else if (millis < 90 * MINUTE_MILLIS) {
tmp = "an hour ago";
} else if (millis < 24 * HOUR_MILLIS) {
tmp = String::format("%.2f", millis / HOUR_MILLIS) + " hours";
} else if (millis < 48 * HOUR_MILLIS) {
tmp = "since yesterday";
} else {
tmp = String::format("%.1f", millis / DAY_MILLIS) + " days";
}
return tmp
]
rule "Openhab Uptime"
when
Time cron "0/10 * * * * ?"
then
val runtime = ManagementFactory::getRuntimeMXBean();
val long startedMillis = runtime.getStartTime()
if(Openhab_Started.state == NULL || Openhab_Started.state == UNDEF) {
Openhab_Started.postUpdate(new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochMilli(startedMillis), ZoneOffset.UTC)))
}
var uptimeAsText = formatDurationToText.apply(now.millis - startedMillis)
postUpdate(Openhab_Uptime, uptimeAsText)
end
rule "CPU Uptime readable"
when
Item CPU_Uptime changed or
Time cron "0/10 * * * * ?"
then
if(CPU_Uptime.state != NULL && CPU_Uptime.state != UNDEF) {
// CPU_Uptime is in minutes, convert it to millis
var cpuUptimeMillis = (CPU_Uptime.state as Number).longValue * 60 * 1000
var uptimeAsText = formatDurationToText.apply(cpuUptimeMillis)
postUpdate(CPU_Uptime_Text, uptimeAsText)
} else {
postUpdate(CPU_Uptime_Text, "-")
}
end
EDIT 2023-11-12: I noticed that runtime.getStartTime() can return the time in local epoch milli… I worked around these issues using uptime:
// We calculate JVM start time using uptime
// runtime.startTime epoch milli can be in UTC millis or local millis, making
// it less convenient
var Instant = Java.type("java.time.Instant");
var startedZoned = ZonedDateTime.ofInstant(
Instant.now().minusMillis(runtime.getUptime()),
ZoneId.systemDefault())
Openhab_Started.postUpdate(new DateTimeType(startedZoned )