HowTo: Create Annotations in Grafana via rules

Here is a short HowTo about creating Annotations in Grafana via Rules in openHAB.

What are Annotations?

Annotations are “markers” that can be displayed inside your Grafana graphs to provide more information about your data.

see: http://docs.grafana.org/reference/annotations/

How to create Annotations via openHAB

Annotations can be created via the HTTP-API.
So it is possible to create them via the HTTP Actions.

To create a single Annotation at this moment you simply need to execute this commands via a rule.

sendHttpPostRequest("http://admin:mySecretPassword@myGrafanaServer:3000/api/annotations", "application/json", '{"tags":["tag1"],"text":"your description"}')

For better readability you can use some variables:

var String url = "http://admin:mySecretPassword@myGrafanaServer:3000/api/annotations"
var String json = '{
    "tags":["test"],
    "text":"your description"
}'
sendHttpPostRequest(url, "application/json", json)

You can find more information about the API here: http://docs.grafana.org/http_api/annotations/

Display Annotations in your Dashboard

To display Annotations you did not created by hand in the Grafana Webinterface you need to go to Settingsof your Dashboard (gears symbol in the right top) and select Annotationson the left menu.
Then you click New to create a new Query.
Define a name and select Tagsas the filter.

Delete the last Annotation an create a new one with region

In this example I will create a normal annotation when an event happens (Test == ON).
Once Testgoes back to OFF the previous Annotation will be deleted and a new Annotation will created that will range from the time the item changed to ON to the current time is changed to OFF.

var long last_Test_On  = now.millis
var long last_Test_Off = now.millis
var long last_AnnotationId_On = 0

rule "Test"
    when
        Item Test changed
    then
        logInfo("Test", "Test")
        var String json
        var String url = "http://admin:mySecretPassword@myGrafanaServer:3000/api/annotations"

        if ( Test.state == ON) {
            last_Test_On = now.millis
            json = '{
                "time":' + Long::toString(last_Test_On) + ',
                "tags":["test"],
                "text":"start"
            }'
            logInfo("Test",  "url:  " + url)
            logInfo("Test", "json: " + json)

            var output = sendHttpPostRequest(url, "application/json", json)

            logInfo("Test",  "output:  " + output)

			// Save Annotation-ID to use it later
            last_AnnotationId_On = Long.parseLong(transform("JSONPATH","$.id", output))
            logInfo("Test",  "last_AnnotationId_On:  " + last_AnnotationId_On)
        } else {
            last_Test_Off = now.millis
            json = '{
                "time":' + Long::toString(last_Test_On) + ',
                "isRegion":true,
                "timeEnd":' + Long::toString(last_Test_Off) + ',
                "tags":["test"],
                "text":"start to stop"
            }'
            logInfo("Test",  "url:  " + url)
            logInfo("Test", "json: " + json)

            var output = sendHttpPostRequest(url, "application/json", json)

            logInfo("Test",  "output:  " + output)

            // Delete old Annotation
			var String delete_url = url + "/" + last_AnnotationId_On
            var delete_output = sendHttpDeleteRequest(delete_url)
            logInfo("Test",  "delete_url:  " + delete_url)
            logInfo("Test",  "delete_output:  " + delete_output)
        }
end

(You might want to delete some of the LogInfo commands.)

ToDo

I am not sure, but it might be possible and more secure to create an API keyin Grafana instead of using the admin user with the clrear text password.
But I don’t know how to pass the key via sendHttpPostRequest.

This method saves the Annotations in Grafana.
It is possible to do that in InfluxDB.
But I don’t know if that is better and how to do so.

12 Likes

Thank you. I can see a number of cases where i can use this.

I edited the first post a little.

I am now using VScode and openHAB 2.4-milestone3.

VScode showed this error.

Type mismatch: cannot convert from String to long

So I added Long.parseLong() to

last_AnnotationId_On = Long.parseLong(transform("JSONPATH","$.id", output))

VScode does not show the error anymore.
But I did not test if everything works now.

Hi Christoph,

thanks for your HowTo :slight_smile:
I used your rule and added the API key authentication.

val String GrafanaAPIKey = "<YourAPIkey>"
val String GrafanaAPIUser = "api_key"

var String url = "http://" + GrafanaAPIUser + ":" + GrafanaAPIKey + "@<yourGrafanaServer>:3000/api/annotations"

kind regards
Michael

1 Like