13 | Addons are designed to let you add more functionality to RPi-Monitor.
14 |
15 |
16 | This release of RPi-Monitor provides the following addons:
17 |
18 |
about - This addon
19 |
example - Example of addons showing how to develop addons that are fully integrated with RPi-Monitor
20 |
custom - Custom addon using <iframe> to display external html page. This
21 | addon is use for shellinabox or Hawkeye webcam -
22 | See documentation for details.
23 |
top3 - Show the top 3 processes using cpu and rpimonitord cpu usage
24 |
25 |
26 | Addons are configured through /etc/rpimonitor/data.conf. You can customize the RPi-Monitor configuration to add or remove addons.
27 |
28 |
29 | Refer to comments in configuration file to see in detail how to manage and use addons.
30 |
13 | Custom addon is design to let you add custom pages to
14 | RPi-Monitor easily.
15 |
16 | This addons is using <iframe> to display external
17 | html page, web site or anything else that can be displayed by your
18 | browser. The url to be displayed is configurable in
19 | RPi-Monitor configuration file and/or in Options dialog box.
20 | You can use custom addon many time in the same configuration and
21 | configure each addons individually.
22 |
23 | Refer to documentation to
24 | see example of usages.
25 |
7 | Example addon shows how you can develop your own addon for
8 | RPi-Monitor.
9 |
10 | An addon (named for this example example) is composed
11 | by a set of 3 files stored in the subdirectory of the same name
12 | /usr/share/rpimonitor/web/addons/example/:
13 |
18 | These 3 files are directly used by RPi-Monitor to render a page.
19 | Javascript of the addon have a direct access to RPi-Monitor
20 | data using the functions in rpimonitor.utils.js and the
21 | functions getData('json_data').
22 |
23 | This example is showing how to get uptime information and display it
24 | using the function Uptime( value ):
25 |
26 |
addonInsertionPoint
27 | Refer to documentation to see example of usages.
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/addons/example/example.js:
--------------------------------------------------------------------------------
1 | var activePage = GetURLParameter('activePage');
2 | if (activePage == null){ activePage = 0; }
3 |
4 | function UpdateAddon () {
5 | $.getJSON('dynamic.json', function(data) {
6 | // Concatenate dynamic.json and static.json into data variable
7 | $.extend(data, getData('static'));
8 |
9 | //ADD YOUR JAVASCRIPT HERE
10 | //Example using data from RPi-Monitor and function provided by rpimonitor.utils.js
11 | textToDisplay = "Uptime: " + Uptime(data.uptime);
12 | $("#addonInsertionPoint").html(textToDisplay)
13 |
14 | })
15 | }
16 |
17 | $(function () {
18 | alert('Example addons is showing how to dynamically display Raspberry Pi uptime.\n'+
19 | 'Have a look to "addonInsertionPoint" bellow and click OK')
20 |
21 | options = '
'+
22 | 'Example '+
23 | '
'+
26 | ''
27 | $(options).insertBefore("#optionsInsertionPoint")
28 | UpdateAddon();
29 |
30 | //if ( statusautorefresh ) {
31 | // refreshTimerId = setInterval( UpdateAddon , 10000 )
32 | // clockId=setInterval(Tick,1000);
33 | //}
34 |
35 | });
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/addons/top3/top3:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | #
3 | # Copyright 2013-2014 - Xavier Berger - http://rpi-experiences.blogspot.fr/
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | #
18 | # web.status.1.content.1.line.4=InsertHTML("/addons/top3/top3.html")
19 | #
20 | my $process='rpimonitor';
21 | my $web=1;
22 | my $nbtop=3;
23 | my @top=[];
24 | my $monitored;
25 |
26 | #Get uptime
27 | my $uptime;
28 | open ( FILE, "/proc/uptime") or die "Can't open /proc/uptime \n";
29 | while (){
30 | /(\S+) \S+/;
31 | $uptime = $_;
32 | }
33 |
34 | my $idx=0;
35 | open (PS, 'ps -e -o etimes,time,comm --sort -time |') or die;
36 | while ()
37 | {
38 | /TIME/ and next;
39 | $idx++;
40 | /$process/ and $monitored->{'idx'} ||= $idx;
41 | /$process/ or $idx <= $nbtop or next;
42 | /(\S+) (\S+):(\S+):(\S+) (\S+)/;
43 | $1 or next;
44 | my $start=100*($2*60*60+$3*60+$4)/$1;
45 | my $total=100*($2*60*60+$3*60+$4)/$uptime;
46 | $web
47 | and $top[$idx] = sprintf("
%3d
%02d:%02d:%02d
%-12s
( %.2f% / %.2f% )
\n",$idx, $2, $3, $4, $5, $start, $total)
48 | or $top[$idx] = sprintf("%3d %02d:%02d:%02d %-12s ( %.2f% / %.2f% ) \n",$idx, $2, $3, $4, $5, $start, $total);
49 | }
50 | close PS or die;
51 | my $iloop;
52 |
53 | $web
54 | and print "
12 | Top3 is design show the 3 process consuming the CPU time of
13 | CPU in addition to cunsumption of rpimonitord process.
14 |
15 | To activate this addon, copy /usr/share/rpimonitor/web/addons/top3/top3.cron
16 | to /etc/cron.d/top3.
17 |
18 | Adding the top3 information into status page can be done by uncommenting
19 | the following line into cpu.conf
20 | #web.status.1.content.1.line.4=InsertHTML("/addons/top3/top3.html")
21 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/js/flot/jquery.flot.selection.min.js:
--------------------------------------------------------------------------------
1 | (function(a){function b(k){var p={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var m={};var r=null;function e(s){if(p.active){l(s);k.getPlaceholder().trigger("plotselecting",[g()])}}function n(s){if(s.which!=1){return}document.body.focus();if(document.onselectstart!==undefined&&m.onselectstart==null){m.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&m.ondrag==null){m.ondrag=document.ondrag;document.ondrag=function(){return false}}d(p.first,s);p.active=true;r=function(t){j(t)};a(document).one("mouseup",r)}function j(s){r=null;if(document.onselectstart!==undefined){document.onselectstart=m.onselectstart}if(document.ondrag!==undefined){document.ondrag=m.ondrag}p.active=false;l(s);if(f()){i()}else{k.getPlaceholder().trigger("plotunselected",[]);k.getPlaceholder().trigger("plotselecting",[null])}return false}function g(){if(!f()){return null}var u={},t=p.first,s=p.second;a.each(k.getAxes(),function(v,w){if(w.used){var y=w.c2p(t[w.direction]),x=w.c2p(s[w.direction]);u[v]={from:Math.min(y,x),to:Math.max(y,x)}}});return u}function i(){var s=g();k.getPlaceholder().trigger("plotselected",[s]);if(s.xaxis&&s.yaxis){k.getPlaceholder().trigger("selected",[{x1:s.xaxis.from,y1:s.yaxis.from,x2:s.xaxis.to,y2:s.yaxis.to}])}}function h(t,u,s){return us?s:u)}function d(w,t){var v=k.getOptions();var u=k.getPlaceholder().offset();var s=k.getPlotOffset();w.x=h(0,t.pageX-u.left-s.left,k.width());w.y=h(0,t.pageY-u.top-s.top,k.height());if(v.selection.mode=="y"){w.x=w==p.first?0:k.width()}if(v.selection.mode=="x"){w.y=w==p.first?0:k.height()}}function l(s){if(s.pageX==null){return}d(p.second,s);if(f()){p.show=true;k.triggerRedrawOverlay()}else{q(true)}}function q(s){if(p.show){p.show=false;k.triggerRedrawOverlay();if(!s){k.getPlaceholder().trigger("plotunselected",[])}}}function c(s,w){var t,y,z,A,x=k.getAxes();for(var u in x){t=x[u];if(t.direction==w){A=w+t.n+"axis";if(!s[A]&&t.n==1){A=w+"axis"}if(s[A]){y=s[A].from;z=s[A].to;break}}}if(!s[A]){t=w=="x"?k.getXAxes()[0]:k.getYAxes()[0];y=s[w+"1"];z=s[w+"2"]}if(y!=null&&z!=null&&y>z){var v=y;y=z;z=v}return{from:y,to:z,axis:t}}function o(t,s){var v,u,w=k.getOptions();if(w.selection.mode=="y"){p.first.x=0;p.second.x=k.width()}else{u=c(t,"x");p.first.x=u.axis.p2c(u.from);p.second.x=u.axis.p2c(u.to)}if(w.selection.mode=="x"){p.first.y=0;p.second.y=k.height()}else{u=c(t,"y");p.first.y=u.axis.p2c(u.from);p.second.y=u.axis.p2c(u.to)}p.show=true;k.triggerRedrawOverlay();if(!s&&f()){i()}}function f(){var s=5;return Math.abs(p.second.x-p.first.x)>=s&&Math.abs(p.second.y-p.first.y)>=s}k.clearSelection=q;k.setSelection=o;k.getSelection=g;k.hooks.bindEvents.push(function(t,s){var u=t.getOptions();if(u.selection.mode!=null){s.mousemove(e);s.mousedown(n)}});k.hooks.drawOverlay.push(function(v,D){if(p.show&&f()){var t=v.getPlotOffset();var s=v.getOptions();D.save();D.translate(t.left,t.top);var z=a.color.parse(s.selection.color);D.strokeStyle=z.scale("a",0.8).toString();D.lineWidth=1;D.lineJoin="round";D.fillStyle=z.scale("a",0.4).toString();var B=Math.min(p.first.x,p.second.x),A=Math.min(p.first.y,p.second.y),C=Math.abs(p.second.x-p.first.x),u=Math.abs(p.second.y-p.first.y);D.fillRect(B,A,C,u);D.strokeRect(B,A,C,u);D.restore()}});k.hooks.shutdown.push(function(t,s){s.unbind("mousemove",e);s.unbind("mousedown",n);if(r){a(document).unbind("mouseup",r)}})}a.plot.plugins.push({init:b,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.1"})})(jQuery);
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/js/flot/jquery.flot.stack.min.js:
--------------------------------------------------------------------------------
1 | (function(b){var a={series:{stack:null}};function c(f){function d(k,j){var h=null;for(var g=0;g2&&(G?g.format[2].x:g.format[2].y),n=u&&v.lines.steps,E=true,q=G?1:0,H=G?0:1,D=0,B=0,A;while(true){if(D>=F.length){break}A=t.length;if(F[D]==null){for(m=0;m=y.length){if(!u){for(m=0;mJ){if(u&&D>0&&F[D-z]!=null){k=w+(F[D-z+H]-w)*(J-x)/(F[D-z+q]-x);t.push(J);t.push(k+I);for(m=2;m0&&y[B-h]!=null){r=I+(y[B-h+H]-I)*(x-J)/(y[B-h+q]-J)}t[A+H]+=r;D+=z}}E=false;if(A!=t.length&&o){t[A+2]+=r}}}}if(n&&A!=t.length&&A>0&&t[A]!=null&&t[A]!=t[A-z]&&t[A+1]!=t[A-z+1]){for(m=0;m0){k=a("#flotTip")}else{k=a("").attr("id","flotTip");k.appendTo("body").hide().css({position:"absolute"});if(i.defaultTheme){k.css({background:"#fff","z-index":"100",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111"})}}a(j).bind("plothover",function(a,b,e){if(e){var f;if(d.xaxis.mode==="time"||d.xaxes[0].mode==="time"){f=h(i.content,e,g)}else{f=h(i.content,e)}k.html(f).css({left:c.x+i.shifts.x,top:c.y+i.shifts.y}).show()}else{k.hide().html("")}});e.mousemove(f)});var h=function(a,b,c){var d=/%p\.{0,1}(\d{0,})/;var e=/%s/;var f=/%x\.{0,1}(\d{0,})/;var g=/%y\.{0,1}(\d{0,})/;if(typeof b.series.percent!=="undefined"){a=i(d,a,b.series.percent)}if(typeof b.series.label!=="undefined"){a=a.replace(e,b.series.label)}if(typeof c==="function"){a=a.replace(f,c(b.series.data[b.dataIndex][0]))}else if(typeof b.series.data[b.dataIndex][0]==="number"){a=i(f,a,b.series.data[b.dataIndex][0])}if(typeof b.series.data[b.dataIndex][1]==="number"){a=i(g,a,b.series.data[b.dataIndex][1])}return a};var i=function(a,b,c){var d;if(b.match(a)!=="null"){if(RegExp.$1!==""){d=RegExp.$1;c=c.toFixed(d)}b=b.replace(a,c)}return b}};a.plot.plugins.push({init:c,options:b,name:"tooltip",version:"0.4.4"})})(jQuery)
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/js/javascriptrrd/rrdMultiFile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Combine multiple rrdFiles into one object
3 | * It implements the same interface, but changing the content
4 | *
5 | * Part of the javascriptRRD package
6 | * Copyright (c) 2010 Igor Sfiligoi, isfiligoi@ucsd.edu
7 | *
8 | * Original repository: http://javascriptrrd.sourceforge.net/
9 | *
10 | * MIT License [http://www.opensource.org/licenses/mit-license.php]
11 | *
12 | */
13 |
14 | // ============================================================
15 | // RRD RRA handling class
16 | function RRDRRASum(rra_list,offset_list,treat_undefined_as_zero) {
17 | this.rra_list=rra_list;
18 | this.offset_list=offset_list;
19 | this.treat_undefined_as_zero=treat_undefined_as_zero;
20 | this.row_cnt= this.rra_list[0].getNrRows();
21 | }
22 |
23 | RRDRRASum.prototype.getIdx = function() {
24 | return this.rra_list[0].getIdx();
25 | }
26 |
27 | // Get number of rows/columns
28 | RRDRRASum.prototype.getNrRows = function() {
29 | return this.row_cnt;
30 | }
31 | RRDRRASum.prototype.getNrDSs = function() {
32 | return this.rra_list[0].getNrDSs();
33 | }
34 |
35 | // Get RRA step (expressed in seconds)
36 | RRDRRASum.prototype.getStep = function() {
37 | return this.rra_list[0].getStep();
38 | }
39 |
40 | // Get consolidation function name
41 | RRDRRASum.prototype.getCFName = function() {
42 | return this.rra_list[0].getCFName();
43 | }
44 |
45 | RRDRRASum.prototype.getEl = function(row_idx,ds_idx) {
46 | var outSum=0.0;
47 | for (var i in this.rra_list) {
48 | var offset=this.offset_list[i];
49 | if ((row_idx+offset) undefined*/
54 | val=undefined;
55 | }
56 | /* treat all undefines as 0 for now */
57 | if (val==undefined) {
58 | if (this.treat_undefined_as_zero) {
59 | val=0;
60 | } else {
61 | /* if even one element is undefined, the whole sum is undefined */
62 | outSum=undefined;
63 | break;
64 | }
65 | }
66 | outSum+=val;
67 | }
68 | return outSum;
69 | }
70 |
71 | // Low precision version of getEl
72 | // Uses getFastDoubleAt
73 | RRDRRASum.prototype.getElFast = function(row_idx,ds_idx) {
74 | var outSum=0.0;
75 | for (var i in this.rra_list) {
76 | var offset=this.offset_list[i];
77 | if ((row_id+offset) undefined*/
82 | val=undefined;
83 | }
84 | /* treat all undefines as 0 for now */
85 | if (val==undefined) {
86 | if (this.treat_undefined_as_zero) {
87 | val=0;
88 | } else {
89 | /* if even one element is undefined, the whole sum is undefined */
90 | outSum=undefined;
91 | break;
92 | }
93 | }
94 | outSum+=val;
95 | }
96 | return outSum;
97 | }
98 |
99 | /*** INTERNAL ** sort by lastupdate, descending ***/
100 |
101 | function rrdFileSort(f1, f2) {
102 | return f2.getLastUpdate()-f1.getLastUpdate();
103 | }
104 |
105 | /*
106 | * Sum several RRDfiles together
107 | * They must all have the same DSes and the same RRAs
108 | */
109 |
110 | function RRDFileSum(file_list,treat_undefined_as_zero) {
111 | if (treat_undefined_as_zero==undefined) {
112 | this.treat_undefined_as_zero=true;
113 | } else {
114 | this.treat_undefined_as_zero=treat_undefined_as_zero;
115 | }
116 | this.file_list=file_list;
117 | this.file_list.sort();
118 |
119 | // ===================================
120 | // Start of user functions
121 |
122 | this.getMinStep = function() {
123 | return this.file_list[0].getMinStep();
124 | }
125 | this.getLastUpdate = function() {
126 | return this.file_list[0].getLastUpdate();
127 | }
128 |
129 | this.getNrDSs = function() {
130 | return this.file_list[0].getNrDSs();
131 | }
132 |
133 | this.getDSNames = function() {
134 | return this.file_list[0].getDSNames();
135 | }
136 |
137 | this.getDS = function(id) {
138 | return this.file_list[0].getDS(id);
139 | }
140 |
141 | this.getNrRRAs = function() {
142 | return this.file_list[0].getNrRRAs();
143 | }
144 |
145 | this.getRRAInfo = function(idx) {
146 | return this.file_list[0].getRRAInfo(idx);
147 | }
148 |
149 | this.getRRA = function(idx) {
150 | var rra_info=this.getRRAInfo(idx);
151 | var rra_step=rra_info.getStep();
152 | var realLastUpdate=undefined;
153 |
154 | var rra_list=new Array();
155 | var offset_list=new Array();
156 | for (var i in this.file_list) {
157 | file=file_list[i];
158 | fileLastUpdate=file.getLastUpdate();
159 | if (realLastUpdate!=undefined) {
160 | fileSkrew=Math.floor((realLastUpdate-fileLastUpdate)/rra_step);
161 | } else {
162 | fileSkrew=0;
163 | firstLastUpdate=fileLastUpdate;
164 | }
165 | offset_list.push(fileSkrew);
166 | fileRRA=file.getRRA(idx);
167 | rra_list.push(fileRRA);
168 | }
169 |
170 | return new RRDRRASum(rra_list,offset_list,this.treat_undefined_as_zero);
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/js/rpimonitor.addons.js:
--------------------------------------------------------------------------------
1 | // This file is part of RPi-Monitor project
2 | //
3 | // Copyright 2014 - Xavier Berger - http://rpi-experiences.blogspot.fr/
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 | function ConstructPage()
18 | {
19 | var activePage = GetURLParameter('activePage');
20 | if (activePage == null){ activePage = 0; }
21 |
22 | data = getData('addons');
23 | if ( ( typeof activePage == 'undefined') ||
24 | ( activePage >= data.length )
25 | )
26 | {
27 | activePage = 0
28 | }
29 | if ( data[activePage].showtitle !== 'false' ) {
30 | $('
'+eval(data[activePage].title)+'
').insertBefore("#insertionPoint");
31 | }
32 |
33 | $("#insertionPoint").load("addons/"+data[activePage].addons+"/"+data[activePage].addons+".html")
34 |
35 | $("head").append("");
36 |
37 | jQuery.ajax({
38 | url: "addons/"+data[activePage].addons+"/"+data[activePage].addons+".js",
39 | dataType: "script",
40 | }).done(function() {
41 | });
42 |
43 | }
44 |
45 | $(function () {
46 | /* Set no cache */
47 | $.ajaxSetup({ cache: false });
48 |
49 | /* Show friends */
50 | ShowFriends();
51 |
52 | /* Add qrcode shortcut*/
53 | setupqr();
54 | doqr(document.URL);
55 |
56 | /* Get static values once */
57 | ConstructPage();
58 | });
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/js/rpimonitor.index.js:
--------------------------------------------------------------------------------
1 | // This file is part of RPi-Monitor project
2 | //
3 | // Copyright 2013 - Xavier Berger - http://rpi-experiences.blogspot.fr/
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 | $(function () {
18 | ShowFriends();
19 | /* Add qrcode shortcut*/
20 | setupqr();
21 | doqr(document.URL);
22 | });
23 |
--------------------------------------------------------------------------------
/src/usr/share/rpimonitor/web/statistics.html:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 | RPi-Monitor
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |