Checking for openHAB updates - simple rule

rules
update
openhabian
Tags: #<Tag:0x00007f6ce47ad6b0> #<Tag:0x00007f6ce47ad520> #<Tag:0x00007f6ce47ad3b8>

(Kuba Wolanin) #1

I’d like to share my little openHAB rule that periodically checks for the new openHAB unstable build.
The script visits openHAB Jenkins page on Cloudbees (this REST API endpoint to be specific) every midnight and then compares the build number with my local build.

A few remarks:

  • I’m running openHABian on Raspberry PI 3B.
    The solution should work on any linux-based setup though.
  • I’m using Unstable (SNAPSHOT) openHAB build (here you’ll find more on that)
  • You need JSONPATH transformation add-on installed

Screenshot

Usage

You can modify the rule so it sends a notification/email/whatever to you.
Or you can go one step further and programmatically update your openHAB… from openHAB!
Well, I didn’t think it’s a good idea at the time but YMMV :wink:

Files

/scripts/check-oh-build.sh

sed -n 's/build-no\s*: //p' /var/lib/openhab2/etc/version.properties | cut -d '#' -f 2
  • Place the check-oh-build.sh file in /etc/openhab2/scripts/
  • user@openhabianpi:/etc/openhab2/scripts $ chmod 777 check-oh-build.sh (or maybe there’s a better way - please share in comments!)

/items/update.items

Switch OH_CheckForUpdates "OH: Check for updates"
String OH_Status          "OH: Status [%s]"

sitemap

sitemap something {
...

  Frame label="openHAB Update" {
    Switch item=OH_CheckForUpdates
    Text item=OH_Status
  }
...
}

/rules/update.rules

rule "Check for openHAB distro updates"
when
    Time is midnight or
    Item OH_CheckForUpdates received command ON
then
    OH_Status.postUpdate("Checking...")

    var String cloudbeesUrl =
        "https://openhab.ci.cloudbees.com/job/openHAB-Distribution/api/json?tree=lastSuccessfulBuild[number]"
    var String currentBuild =
        executeCommandLine("/etc/openhab2/scripts/check-oh-build.sh", 2000)

    // logInfo("update", "currentBuild: " + currentBuild)

    var response = sendHttpGetRequest(cloudbeesUrl)
    var lastBuildNumber = transform("JSONPATH", "$.lastSuccessfulBuild.number", response)
    // logInfo("update", "lastBuild: " + lastBuildNumber)

    if (Integer.parseInt(currentBuild) < Integer.parseInt(lastBuildNumber)) {
        OH_Status.postUpdate("Update available: #" + lastBuildNumber)
        // Do something with that information
    } else {
        OH_Status.postUpdate("No updates")
    }

    OH_CheckForUpdates.postUpdate(OFF)
end

Aaand that’s it!
Not sure if it’s very useful, but at least it’s a good excercise on:

  • getting data from remote JSON file
  • running local Bash scripts

in openHAB.

Happy hacking!


SiteMap Visibility comparing 2 Number Items
Compare Build Number to jfrog or bintray?
Cannot find it
(Jerome) #2

Excellent. :+1:

One small comment:
I would use a mapping like mappings=[ON="Check now!"]in the sitemap for the switch, to make it look like a button instead of a switch.
I know it’s some silly optical thing, but it is a thing. :smile:


(Rich Koshak) #3

This is a fantastic idea. Thanks for posting!

You could make the rule slightly simpler, at the cost of no longer checking exactly at midnight, by using the HTTP binding cached configuration. You could then just have a OH_Version Item with the transform on it and trigger your Rule when OH_Version changes. Something like:

http.cfg

openhabVersion.url="https://openhab.ci.cloudbees.com/job/openHAB-Distribution/api/json?tree=lastSuccessfulBuild[number]"
openhabVersion.updateIInterval=518400000 // every 24 hours, I'd use something smaller like every two or four hours

items

String OH_LastBuild "OH: Status [%s]" { http="<[openhabVersion:518400000:JSONPATH($.lastSuccessfulBuild.number)]" }

rules

// I've never called executCommandLine to populate a global val like this, if it doesn't work use a System started rule
// The version of OH will not change while OH is running so we only need to call this script once
val lastBuildNumber = new Integer(executeCommandLine("/etc/openhab2/scripts/check-oh-build.sh", 2000))

rule "OH's Build Status Changed"
when
    Item OH_LastBuild changed
then
    val currentBuild = new Integer(OH_LastBuild.state.toString)

    if(currentBuild < lastBuildNumber) {
        OH_Status.postUpdate("Update available: #" + OH_LastBuild.state.toString)
        // alerts go here
    }
    else OH_Status.postUpdate("No updates")
end

You can remove the check Item from the sitemap since OH will automatically check.

It used to be a problem placing shell scripts in the OH scripts folder but am not certain it still is. The problem is that folder was intended to be for OH scripts, not generic shell scripts and the start script that runs OH used to go and change the permissions on all the files in the conf folder stripping off the execute permissions. Because of that I recommend putting all scripts like this into ~openhab/bin or the like. For an apt-get installation ~openhab is /var/lib/openhab2 unless you created the openhab user yourself prior to installing OH.

Also, the permissions on the script probably don’t need to be all that open. I would do:

chown openhab:openhab check-oh-build.sh
sudo chmod ug=rwx,o=rx check-oh-build.sh
```

This will set the ownership of the file to openhab and give everyone execute permission but only the openhab user or group has write permissions. I make sure my login user is a member of the openhab group and all works out well.

Theoretically, since the shell script is a one-liner it could be just written as the command send to executeCommandLine but we all know how finicky it can be to get a command like this to run right with the @@ and escaping the quotes and such.

Great posting!

(Kuba Wolanin) #4

Thanks @rlkoshak for a great follow up for this!

I’ll definitely use your approach :wink:

Note that there was a typo in updateInterval in your example. And the URL must be encoded first (so special characters must be replaced with %5E etc).

oh.url="https://openhab.ci.cloudbees.com/job/openHAB-Distribution/api/json?tree=lastSuccessfulBuild%5Bnumber%5D"
oh.updateInterval=259200000

Cheers!


(Paul Muldoon) #5

I setup the http binding and cfg per above, but I keep getting this in my logs and can’t seem to figure out why.

2017-12-04 21:54:06.612 [INFO ] [b.core.service.AbstractActiveService] - HTTP Refresh Service has been started
2017-12-04 21:54:06.613 [ERROR] [b.core.service.AbstractActiveService] - Error while executing background thread HTTP Refresh Service
java.lang.NullPointerException: null

(Marco Salinardi) #6

Was really into implementig this and could not get it working.
Checked the problem and the complete procedure is a mixing of @kubawolanin and @rlkoshak

items

String OH_LastBuild "OH: LastBuild[%s]" { http="<[openhabVersion:518400000:JSONPATH($.lastSuccessfulBuild.number)]" }
String OH_Status "OH: Status [%s]"

on rules

// previously confused with lastBuildNumber
val currentBuild = new Integer(executeCommandLine("/etc/openhab2/scripts/check-on-build.sh", 2000))

rule "OH's Build Status Changed"
when
    Item OH_LastBuild changed
then
    val lastBuildNumber = new Integer(OH_LastBuild.state.toString)

    if(currentBuild < lastBuildNumber) {
        OH_Status.postUpdate("Update available: #" + OH_LastBuild.state.toString)
        // alerts go here
    }
    else OH_Status.postUpdate("Updated version")
end

(Rich Koshak) #7

What specifically is the problem? Do you get errors? The Rule doesn’t trigger? Incorrect value?

I know that Kuba is actively running with his code so what he posted should work.


(Alex) #8

Good job of all! :slight_smile:

For this I simply use the feed binding.

URL: https://openhab.ci.cloudbees.com/job/openHAB-Distribution/rssAll

.items

String cb_title                	"title"  				(News)	{channel="feed:feed:255f7361:title"}
String cb_latest_title   		"latest title"		    (News)	{channel="feed:feed:255f7361:latest-title"}
DateTime cb_latest_date        	"latest date"			(News)	{channel="feed:feed:255f7361:latest-date"}
DateTime cb_published_date 		"published date"		(News)	{channel="feed:feed:255f7361:last-update"}

(Marco Salinardi) #9

in the code you posted

val lastBuildNumber = new Integer(executeCommandLine("/etc/openhab2/scripts/check-oh-build.sh", 2000))

this is actually the current version

val currentBuild = new Integer(OH_LastBuild.state.toString)

this will provide the lastest version and not the current one

    if(currentBuild < lastBuildNumber) {

this line will never be true because the two value where exchanged


(Rich Koshak) #10

I’m not surprised if there are errors in the code I posted. It was intended as notional approach, not as a completely tested set of rules known to work.


(Marco Salinardi) #11

I have not blaimed anyone, just find it not working and posted a solution. Sorry i am pretty new to post contributes because i have not too muck programming skills. I just wanted to help someone like me that would have liked to use this rule ;(


(Marco Salinardi) #12

what url did you provided for the feed binding?


(Alex) #13

@Melkor

URL: https://openhab.ci.cloudbees.com/job/openHAB-Distribution/rssAll

.items:

String cb_title                	"title"  				(News)	{channel="feed:feed:255f7361:title"}
String cb_latest_title   		"latest title"		    (News)	{channel="feed:feed:255f7361:latest-title"}
DateTime cb_latest_date        	"latest date"			(News)	{channel="feed:feed:255f7361:latest-date"}
DateTime cb_published_date 		"published date"		(News)	{channel="feed:feed:255f7361:last-update"}

(Rich Koshak) #14

No problem, I didn’t think you were blaming me. Just explaining how the error could have ended up in the log.

I think it will work if you swap the < with a > or even a !=


(Holger Eisold) #15

hey guys… thanks for this awesome rule…

First i run into some problems with the code suggestions from @rlkoshak but finally I got it fixed… and it helped me to understand things better… so here is my working example:

http.cfg file

# configuration of the first cache item
openhabVersion.url="https://openhab.ci.cloudbees.com/job/openHAB-Distribution/api/json?tree=lastSuccessfulBuild%5Bnumber%5D"
openhabVersion.updateInterval=518400000

check-oh-build.sh file

sed -n 's/build-no\s*: //p' /var/lib/openhab2/etc/version.properties | cut -d '#' -f 2

.sitemap file

	Frame label="openHAB Update" {
		Text item=OH_Status
	}

.rules file

val currentBuild = new Integer(executeCommandLine("/etc/openhab2/scripts/check-oh-build.sh", 2000))

rule "openhab build status changed"
when
	Time is midnight or
    System started
then
    val lastBuildNumber = new Integer(OH_LastBuild.state.toString)

    if(currentBuild < lastBuildNumber) {
        OH_Status.postUpdate("Update available: #" + OH_LastBuild.state.toString)
        Thread::sleep(3000)
        sendTelegram("bot1", "openHAB has been started. There is a new update available!\n\nCurrent Build Number: " + currentBuild + "\nNew Build Number: " + lastBuildNumber)
    }
    else {
    	OH_Status.postUpdate("Updated version")
    	Thread::sleep(3000)
    	sendTelegram("bot1", "openHAB has been started and is performing on the lastest build.")
    }
end

(Hallo Ween) #16

Why have you made

rule "openhab build status changed"
when
	Time is midnight or
        System started
then

as trigger for your rule?

Wouldn´t it be better to make

when
    Item OH_LastBuild changed
then

as the trigger?


(Hallo Ween) #17

Is there a way to read out the date of the file /var/lib/openhab2/etc/version.properties to get the date/time of the latest update which was made on the openhab server?


(Rich Koshak) #18
val date = executeCommandLine("ls -l /var/lib/userdata/etc/version.properties | cut -d ' ' -f 6-8")

(Hallo Ween) #19

I have found this, and it seems to work too:

#!/bin/bash
stat -c %z /var/lib/openhab2/etc/version.properties | cut -f2  | cut -c1-19

I can read out three times with “stat”. access-time / modification time / ctime (or something like this)

access-time is unusable for me.

What is the difference between the two others? I have read a description about it, but i don´t know which time is the right one, when i want to check for latest openhab-update?

In my case modification time and the last time (ctime?) is not the same.

modification time is 2nd january, ctime is 3rd january. I made an update on 3rd january.

But what i have read in the description, modification time should have been the right one???

In your exec-command there is also this command --> %z

This is the third time (ctime?).

%y would be the modification time.


(Ganesh) #20

Folks, sometimes upgrade is not simply about changing jars, there is data migration too. e.g config parameterX in a binding is now a boolean instead of integer and config parameterY is removed. Ideally the later version of the binding code should do the data migration smoothly, but it may not be as simple as that all the time to automate such a thing. A conscious human being may be required to do the migration. In such a case, the release should explicitly mention manual steps and this auto upgrade rule/binding/extension (the thing you guys are discussing here) should have a mechanism to report this to user and preferably not do a known complex upgrade all by itself, instead generate a set of commands / instructions to do the upgrade.