New charting solution for openHAB

Remark : the installation procedure has been simplified, as you can read here:

Hi,

Actually we have a charting solution to propose for openHAB. (1.8.x)
Since the aim is to make this as accessible as possible, it would be nice if some people could have a try and give some feedback.

The ultimate goal is to be able to create a chart, just by adding some logging and inserting a link in the sitemap.
However, to be able to make it work with the actual state of openHAB, a modification has to be made in org.openhab.ui.webapp_1.8.x.jar in order to use the Webview of the sitemap (as explained below).

To have an idea of what the charts looks like, have a look at www.intchart.com.

These are the steps involved to make it work.
(as example a chart will be created for the Weather_Temperature and Weather_Humidity of the demo)

1. Create the rules

Insert in the head of the rules file:

import java.io.*

Then create the rules

// write first line to file (line names)
rule "Initialize Logging"
when 
	System started
then 	
	var String path = new File("").getAbsolutePath()+'\\webapps\\data\\data.txt'
	var File f = new File(path)
	var String line

// check if file empty
if(f.exists()){
var RandomAccessFile fileHandler = new RandomAccessFile(path, “r” );
line = fileHandler.readLine();

  logInfo("",'First time read');

}

// if file doesn’t exists or if file is empty
if(!f.exists() || (line==null)){
var BufferedWriter w = new BufferedWriter(new FileWriter(f, true));

  // ** change header here **
  w.write('date;Weather_Temperature;Weather_Humidity');	
  
  w.newLine();
  w.close();	
  
  logInfo("",'First line written');

}
end

// logging to file
rule "Logging"
when 
  Time cron "0 * * * * ?" // 1 minute
   //Time cron "0 0/10 * * * ?" // 10 minutes
then

// check if number and round to 2 decimal
try {
// ** add, delete or change items here **
var Number state1 = Weather_Temperature.state as DecimalType
var Number state2 = Weather_Humidity.state as DecimalType
var x1 = (Math::round(state1.floatValue10.0))/10.0
var x2 = (Math::round(state2.floatValue
10.0))/10.0

  logInfo("data",""+x1+';'+x2);

} catch (Exception e){
logInfo(“”,‘Uninitialized’);
return false;
}

end

2. Create the logger

In logback.xml add the following lines

<appender name="data" class="ch.qos.logback.core.FileAppender">
	<file>${openhab.logdir:-webapps/data}/data.txt</file>
	<append>true</append>
	<encoder>
		<pattern>%d{yyyy-MM-dd HH:mm:ss};%msg%n</pattern>
	</encoder>
</appender>

<logger name="org.openhab.model.script.data" level="INFO" additivity="false">
	<appender-ref ref="data" />
</logger>

3. Get your access

Get your API user id here: (you’ll have to register first)

(For making charts, you only need the API user id, not the API key)

4. Add a frame to the sitemap

In the sitemap, at the location you like, insert the following link
(replace {user_id} by the API user id you got in step 3)

Frame {
 	Webview url="https://www.intchart.com/api/{user_id}/chart/data.txt?path=data&width=1200&smooth=0.9&g_type=av"
}

By adding parameters to the url, you can customise your chart.
To have an idea of all the possible parameters have a look at:

5. Finally change the webapp jar

Like explained in the beginning, in order to be able to use the ‘Webview’, some modifications have to be made to the webapp jar. This was the simplest way to be able to test this implementation, for the following reasons:

  • we had to be able to get the url
  • we could not use an iframe (because the openhab webroot is not accessible from within the iframe)

But attention : this means that the ‘classic’ way of using the Webview will be altered, and during this test you will not be able to have these iframes.

The file to be changed is the following:

....\openhab\server\plugins\org.openhab.ui.webapp_1.8.x.jar

When the jar extracted, the following file has to be modified:

snippets\main.html

The modification is identical for all versions 1.8.x, with a slight difference between (1.8.0 , 1.8.1) and (1.8.2 , 1.8.3).

Insert the ‘beginslide’ listener before the ‘endslide’ listener (all versions 1.8.x) :

  // replace iframe with div
  WA.AddEventListener("beginslide", function () {
      if($("iframe").length>=1 && !OH.intchart){
        OH.intchart = $("iframe").attr('src');
        $("iframe").parent().html('<p><div id="intchart"></div></p>');
      }else{
        OH.intchart = false;
      }
  });

 WA.AddEventListener("endslide", function () {
    ....

Versions 1.8.0 and 1.8.1 : modify the ‘endslide’ listener like this :

  WA.AddEventListener("endslide", function () {
    var search, url;
    var hash = document.location.hash;
    var path = document.location.pathname;
    if (document.location.search) {
      search = document.location.search + "&";
    } else {
      search = "?";
    }
    search = search + "sitemap=%sitemap%&w=" + hash.substring(2) + "&poll=true";
    url = path + search;
    
    /*
    * replace these two lines
    */
    //OH.pollURL = url;
    //OH.pollingRequest = WA.Request(url, null, -1, true, null);
    
    // draw chart and change polling
    if(OH.intchart){
        $("#intchart").load(OH.intchart,
          function (errorText,errorStatus) {
            if (errorStatus == "error") {
              $("#intchart").html(errorText);
            }
        });
        OH.pollURL = '';
        OH.pollingRequest = '';
    }else{
        OH.pollURL = url;
        OH.pollingRequest = WA.Request(url, null, -1, true, null);
    }

    OH.images.refresh = OH.images.countOnPage;
    OH.images.countOnPage = 0;
  });

Versions 1.8.2 and 1.8.3 : modify the ‘endslide’ listener like this :

  WA.AddEventListener("endslide", function () {
    var search, url;
    var hash = document.location.hash;
    var path = document.location.pathname;
    if (document.location.search) {
      search = document.location.search + "&";
    } else {
      search = "?";
    }
    search = search + "sitemap=%sitemap%&w=" + hash.substring(2) + "&poll=true";
    url = path + search;
    
    /*
     * replace this line
     */
     //WA.Request(url, null, -1, true, null); 
     
     // draw chart and change polling
     if(OH.intchart){
         $("#intchart").load(OH.intchart,
           function (errorText,errorStatus) {
             if (errorStatus == "error") {
               $("#intchart").html(errorText);
             }
         });
     }else{
    	 WA.Request(url, null, -1, true, null); 
     }
  });

So these are the steps involved to include the charting.
If useful, in the future some enhancements could be made. Like:

  • Include a refresh mechanism (this has been removed now because the whole page is refreshing, and this hinders analysing the chart)
  • Make some changes to the org.openhab.ui.webapp_1.8.x.jar, to be able to use the chart without eliminating the Webview functionality
  • Make a script to make it easy to add the rules
  • Or even create a binding to simplify the overall configuration

So I hope some people some people find it useful to have a try, and I would be happy to get some feedback.

1 Like