Sunday, February 10, 2013

Raspberry Pi, gnuplot and jquery

In my last post, I wrapped up the standby generator project. However, I felt that logging temperatures to a database and not really doing much with them afterwards was not really logical. Either you don’t use them and clean up the database, or, you do something funky with them. In my case, I just cannot bear to get rid of organized, well defined data, so I decided to employ the Pi to display the data in graphs.

This is the end result:

tempgraphweek

Click on the graph to see it in full detail and observer some of the wild temperature swings we see around here.

To create the graphs, I use gnuplot. This cross platform graphing application has been around for many years. In order to produce graphs, you need to, as a minimum, 2 have created 2 files: a config file and a data file.

To install gnuplot on a Raspberry Pi:

sudo apt-get install gnuplot-x11

The config file (gnuplotconfigweek.txt):

   1: set terminal gif small size 600, 500 transparent
   2: set output "images/tempsweek.gif"
   3: set time
   4:  
   5: set xtics rotate
   6: set xdata time
   7: set timefmt "%Y-%m-%d %H:%M:%S"
   8: set format x "%Y-%m-%d"
   9: set y2tics
  10: set grid
  11: set title "Ambient Temperature Trend Per Week"
  12: set ylabel "Degrees Celsius"
  13: set xlabel "\n1 hour interval"
  14: plot 'graphdataweek.txt' using 1:3 title "Ambient" with lines
  15: set key below
  16: set output

The data file (graphdataweek.txt):



   1: 2013-02-03 01:00:00 -15.437
   2: 2013-02-03 02:00:00 -16.25
   3: 2013-02-03 03:00:00 -15.875
   4: 2013-02-03 04:00:00 -15.625
   5: 2013-02-03 05:00:00 -15.25
   6: 2013-02-03 06:00:00 -14.312
   7: 2013-02-03 07:00:00 -13.875
   8: 2013-02-03 08:00:00 -12.812
   9: 2013-02-03 09:00:00 -10.875
  10: 2013-02-03 10:00:00 -7.375
  11: 2013-02-03 11:00:00 -5.562
  12: 2013-02-03 12:00:00 -4.875
  13: 2013-02-03 13:00:00 -2.562
  14: 2013-02-03 14:00:00 -2.312
  15: 2013-02-03 15:00:00 -3.562
  16: 2013-02-03 16:00:00 -5.187
  17: 2013-02-03 17:00:00 -6.75
  18: 2013-02-03 18:00:00 -8.0
  19: 2013-02-03 19:00:00 -8.5
  20: 2013-02-03 20:00:00 -8.937
  21: 2013-02-03 21:00:00 -9.25
  22: 2013-02-03 22:00:00 -8.5
  23: 2013-02-03 23:00:00 -9.0
  24: 2013-02-04 00:00:00 -8.625
  25: 2013-02-04 01:00:00 -8.687
  26: 2013-02-04 02:00:00 -9.5
  27: 2013-02-04 03:00:00 -10.562
  28: 2013-02-04 04:00:00 -11.187
  29: 2013-02-04 05:00:00 -11.5
  30: 2013-02-04 06:00:00 -11.562
  31: 2013-02-04 07:00:00 -11.687
  32: 2013-02-04 08:00:00 -11.25
  33: 2013-02-04 09:00:00 -9.437
  34: 2013-02-04 10:00:00 -3.125
  35: 2013-02-04 11:00:00 -5.375
  36: 2013-02-04 12:00:00 -3.0
  37: 2013-02-04 13:00:00 -2.625
  38: 2013-02-04 14:00:00 -2.937
  39: 2013-02-04 15:00:00 -3.062
  40: 2013-02-04 16:00:00 -4.062
  41: 2013-02-04 17:00:00 -5.062
  42: 2013-02-04 18:00:00 -5.937
  43: 2013-02-04 19:00:00 -6.25
  44: 2013-02-04 20:00:00 -6.562
  45: 2013-02-04 21:00:00 -6.937
  46: 2013-02-04 22:00:00 -7.25
  47: 2013-02-04 23:00:00 -8.125
  48: 2013-02-05 00:00:00 -10.0
  49: 2013-02-05 01:00:00 -11.812
  50: 2013-02-05 02:00:00 -12.562
  51: 2013-02-05 03:00:00 -12.875
  52: 2013-02-05 04:00:00 -13.375
  53: 2013-02-05 05:00:00 -13.5
  54: 2013-02-05 06:00:00 -14.25
  55: 2013-02-05 07:00:00 -15.062
  56: 2013-02-05 08:00:00 -15.312
  57: 2013-02-05 09:00:00 -14.125
  58: 2013-02-05 10:00:00 -9.062
  59: 2013-02-05 11:00:00 -4.437
  60: 2013-02-05 12:00:00 -2.062
  61: 2013-02-05 13:00:00 -1.25
  62: 2013-02-05 14:00:00 -0.812
  63: 2013-02-05 15:00:00 -1.875
  64: 2013-02-05 16:00:00 -3.312
  65: 2013-02-05 17:00:00 -4.562
  66: 2013-02-05 18:00:00 -5.062
  67: 2013-02-05 19:00:00 -5.187
  68: 2013-02-05 20:00:00 -5.125
  69: 2013-02-05 21:00:00 -5.25
  70: 2013-02-05 22:00:00 -4.75
  71: 2013-02-05 23:00:00 -4.25
  72: 2013-02-06 00:00:00 -3.875
  73: 2013-02-06 01:00:00 -3.5
  74: 2013-02-06 02:00:00 -3.562
  75: 2013-02-06 03:00:00 -3.5
  76: 2013-02-06 04:00:00 -4.25
  77: 2013-02-06 05:00:00 -4.625
  78: 2013-02-06 06:00:00 -5.5
  79: 2013-02-06 07:00:00 -6.562
  80: 2013-02-06 08:00:00 -7.437
  81: 2013-02-06 09:00:00 -6.812
  82: 2013-02-06 10:00:00 -5.125
  83: 2013-02-06 11:00:00 -2.062
  84: 2013-02-06 12:00:00 0.187
  85: 2013-02-06 13:00:00 -0.25
  86: 2013-02-06 14:00:00 3.187
  87: 2013-02-06 15:00:00 0.812
  88: 2013-02-06 16:00:00 -0.687
  89: 2013-02-06 17:00:00 -3.437
  90: 2013-02-06 18:00:00 -4.687
  91: 2013-02-06 19:00:00 -5.812
  92: 2013-02-06 20:00:00 -6.75
  93: 2013-02-06 21:00:00 -7.562
  94: 2013-02-06 22:00:00 -8.625
  95: 2013-02-06 23:00:00 -9.625
  96: 2013-02-07 00:00:00 -10.187
  97: 2013-02-07 01:00:00 -10.687
  98: 2013-02-07 02:00:00 -10.0
  99: 2013-02-07 03:00:00 -8.375
 100: 2013-02-07 04:00:00 -7.625
 101: 2013-02-07 05:00:00 -7.062
 102: 2013-02-07 06:00:00 -6.75
 103: 2013-02-07 07:00:00 -6.187
 104: 2013-02-07 08:00:00 -5.5
 105: 2013-02-07 09:00:00 -3.75
 106: 2013-02-07 10:00:00 -1.875
 107: 2013-02-07 11:00:00 0.562
 108: 2013-02-07 12:00:00 0.937
 109: 2013-02-07 13:00:00 1.437
 110: 2013-02-07 14:00:00 0.937
 111: 2013-02-07 15:00:00 0.625
 112: 2013-02-07 16:00:00 -0.25
 113: 2013-02-07 17:00:00 -1.75
 114: 2013-02-07 18:00:00 -2.562
 115: 2013-02-07 19:00:00 -2.812
 116: 2013-02-07 20:00:00 -3.0
 117: 2013-02-07 21:00:00 -3.187
 118: 2013-02-07 22:00:00 -3.625
 119: 2013-02-07 23:00:00 -3.5
 120: 2013-02-08 00:00:00 -3.25
 121: 2013-02-08 01:00:00 -3.062
 122: 2013-02-08 02:00:00 -2.75
 123: 2013-02-08 03:00:00 -2.5
 124: 2013-02-08 04:00:00 -2.437
 125: 2013-02-08 05:00:00 -2.625
 126: 2013-02-08 06:00:00 -2.437
 127: 2013-02-08 07:00:00 -2.187
 128: 2013-02-08 08:00:00 -2.125
 129: 2013-02-08 09:00:00 -1.625
 130: 2013-02-08 10:00:00 -1.062
 131: 2013-02-08 11:00:00 -3.25
 132: 2013-02-08 12:00:00 -4.562
 133: 2013-02-08 13:00:00 -3.687
 134: 2013-02-08 14:00:00 -4.187
 135: 2013-02-08 15:00:00 -4.75
 136: 2013-02-08 16:00:00 -4.187
 137: 2013-02-08 17:00:00 -6.062
 138: 2013-02-08 18:00:00 -6.75
 139: 2013-02-08 19:00:00 -6.937
 140: 2013-02-08 20:00:00 -6.937
 141: 2013-02-08 21:00:00 -7.437
 142: 2013-02-08 22:00:00 -8.687
 143: 2013-02-08 23:00:00 -8.5
 144: 2013-02-09 00:00:00 -8.625
 145: 2013-02-09 01:00:00 -9.937
 146: 2013-02-09 02:00:00 -11.0
 147: 2013-02-09 03:00:00 -10.875
 148: 2013-02-09 04:00:00 -10.937
 149: 2013-02-09 05:00:00 -11.875
 150: 2013-02-09 06:00:00 -13.875
 151: 2013-02-09 07:00:00 -13.75
 152: 2013-02-09 08:00:00 -15.0
 153: 2013-02-09 09:00:00 -13.625
 154: 2013-02-09 10:00:00 -9.5
 155: 2013-02-09 11:00:00 -2.75
 156: 2013-02-09 12:00:00 -2.937
 157: 2013-02-09 13:00:00 -0.375
 158: 2013-02-09 14:00:00 2.312
 159: 2013-02-09 15:00:00 -1.5
 160: 2013-02-09 16:00:00 -3.0
 161: 2013-02-09 17:00:00 -4.187
 162: 2013-02-09 18:00:00 -5.625
 163: 2013-02-09 19:00:00 -7.625
 164: 2013-02-09 20:00:00 -9.25
 165: 2013-02-09 21:00:00 -10.687
 166: 2013-02-09 22:00:00 -11.812
 167: 2013-02-09 23:00:00 -13.125
 168: 2013-02-10 00:00:00 -14.187

This is all you need to produce good looking graphs. However, having a graph available and stored on your machine is one thing. Now it needs to be available on the web.


To do that I decided to add some date input fields on the ‘Manage’ tab of the monitor’s web page. Three fields and 2 buttons to be exact. The first date field allows you to pick a date and generate a week of daily temperatures starting at that date. The second set of 2 allows for a starting and ending range of dates and will generate a graph of high and low temperatures for all dates in between.


This is where jQuery comes in handy. According to Wikipedia, jQuery is a multi-browser JavaScript library designed to simplify the client-side scripting of HTML. In other words, it allows a web site developer to do fairly fancy operations fairly quickly by using a library of functions written in JavaScript that have been previously debugged. If you were foolish enough, you could write your own JavaScript to do all this, but it would be a long and tedious process. And, just when you think it all works properly, it all blows up in your face. Been there, done that.


In order to get properly formatted dates each and every time, I used the datepicker from Keith Wood, since it seemed to be sufficiently small, with lots of options for limiting input ranges, starting dates etc. To use, simply add these 2s line in the <HEAD> section of your HTML:


<link type="text/css" href="jquery.datepick.css" rel="stylesheet" />


<script type="text/javascript" src="jquery.datepick.js"></script>


Of course, you should have jquery itself also installed on this page, so the whole thing should look like this:



   1: <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
   2:     <script type="text/javascript" src="jquery.address-1.4.min.js"></script>
   3:     <script type="text/javascript" src="jquery.datepick.js"></script>
   4:     <script type="text/javascript" src="zebra_dialog.js"></script>


In my case, the jquery.address line is for the tabbed page, and the zebra_dialog is for displaying the graph. More about that later.


So, once you have the reference for the datepicker included in the HTML HEAD section, you can include the code to allow the date popups to be generated anytime a user clicks on a date field.


Still within the HEAD section, I included these lines


   1: <script type="text/javascript">
   2: $(function () {
   3:         $('#popupDatepicker').datepick({ dateFormat: $.datepick.ATOM, minDate: '2012-12-15', maxDate: -7 });
   4:         $('#1popupDatepicker').datepick({ dateFormat: $.datepick.ATOM, minDate: '2012-12-15', maxDate: -7 });
   5:         $('#2popupDatepicker').datepick({ dateFormat: $.datepick.ATOM, maxDate: 0 });
   6:     });
   7: </script>


As you can see, I have references to 3 date fields. I also specify that I would like these in the proper ISO format (i.e YYYY-MM-DD) and any other limits, starting or ending, that I would like to use.


In the actual HTML, the BODY section of it, this is how the date fields are coded:



   1: <form method="POST" action="/showweek">    
   2:                     <p>Show temperature trend for week starting: <input name="week" type="text" id="popupDatepicker" />&nbsp;&nbsp;<input value="Create Week Graph" name="createweekgraph" type="submit" /></p><br />
   3:                 </form>
   4:                 <br /><br />
   5:                 <form method="POST" action="/showextended">
   6:                     <p>Show daily high and low temperatures for the following period:</p><br />
   7:                     <p>Starting date<input name="startdate" type="text" id="1popupDatepicker" /></p><br />
   8:                     <p>Ending date <input name="enddate" type="text" id="2popupDatepicker" />
   9:                     <input value="Create Extended Graph" name="createextendedgraph" type="submit" /></p><br />
  10:                 </form>

You can see that the JavaScript tag #popupDatepicker is matched to popupDatepicker in the body section. Anytime that field is accessed, the date popup will be displayed. Same for the other 2 fields.


So that takes care of date formatting. Next is how to actually display the graphs in an elegant matter, in other words, don’t stick them on an ugly HTML page somewhere and be done with it.


After a lot of searching, I settled for zebra_dialog jquery add in. This add in, like quite a few others, will allow for a window to be opened up in front of a web page, with the background faintly visible. So, in my case, the user fills in a date for a weekly graph for instance, then presses Create Week Graph. Next, the application on Raspberry Pi, creates the graph and returns it to the user’s browser. The browser then first show the graph, and waits for the user to press Ok to close it. Control is then returned to the ‘regular’ web page. If there is no graph to be displayed, then the regular web page opens up, plain and simple.


To get the zebra_dialog to display the graph, this is what is included in the <script type=”text/JavaScript”> section of the HTML page:



   1: $(document).ready(function () {
   2:  
   3:        {{cSlashes}} $.Zebra_Dialog('<img border="0" src="{{cGraphFile}}"><BR><a href="javascript:window.print()"><p style="font-family:arial;color:red;font-size:20px;">Print This Page</p></a>', { 'title': 'Temperature Graph', width: 1000, 'custom_class': 'zclass', animation_speed: 1000, overlay_close: false,'position': ['left + 150', 'top + 30']});
   4:  
   5:     });

The {{cSlashes}} reference is replaced at runtime by the web application with either ‘//’ or ‘’ depending on whether or not a graph needs displaying. The {{cGraphFile}} reference is replaced by the name of the file to be displayed, once again this is done at runtime by the Bottle web application. As you can see, there are quite a few parameters you can specify in order to control the look and feel of the dialog box.


The web page generates surprisingly quickly, even when the longest data range is used (almost two months now). Yet another testament to the Pi’s amazing abilities.