plantwatchdog 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +674 -0
  3. data/Manifest.txt +42 -0
  4. data/README.txt +91 -0
  5. data/Rakefile +22 -0
  6. data/bin/plantwatchdog +8 -0
  7. data/bin/upload_measurements +2 -0
  8. data/config.ru +35 -0
  9. data/config/app_config.yaml +10 -0
  10. data/lib/plantwatchdog/aggregation.rb +220 -0
  11. data/lib/plantwatchdog/aggregation_methods.rb +90 -0
  12. data/lib/plantwatchdog/data.rb +126 -0
  13. data/lib/plantwatchdog/db.rb +37 -0
  14. data/lib/plantwatchdog/gems.rb +5 -0
  15. data/lib/plantwatchdog/main.rb +76 -0
  16. data/lib/plantwatchdog/model.rb +442 -0
  17. data/lib/plantwatchdog/sinatra.rb +206 -0
  18. data/public/images/arrow-down.gif +0 -0
  19. data/public/images/arrow-left.gif +0 -0
  20. data/public/images/arrow-right.gif +0 -0
  21. data/public/images/arrow-up.gif +0 -0
  22. data/public/images/spinner.gif +0 -0
  23. data/public/images/tabs.png +0 -0
  24. data/public/js/customflot.js +120 -0
  25. data/public/js/jquery-1.3.2.min.js +19 -0
  26. data/public/js/jquery.flot.crosshair.js +157 -0
  27. data/public/js/jquery.flot.js +2119 -0
  28. data/public/js/jquery.flot.navigate.js +272 -0
  29. data/public/js/jquery.flot.selection.js +299 -0
  30. data/public/js/select-chain.js +71 -0
  31. data/public/js/tools.tabs-1.0.4.js +285 -0
  32. data/public/tabs.css +87 -0
  33. data/sample/solar/create_solar.rb +31 -0
  34. data/sample/solar/measurements/client.sqlite3 +0 -0
  35. data/sample/solar/static/devices.yml +17 -0
  36. data/sample/solar/static/metadata.yml +30 -0
  37. data/sample/solar/static/plants.yml +3 -0
  38. data/sample/solar/static/users.yml +4 -0
  39. data/sample/solar/upload_measurements +26 -0
  40. data/templates/graph.erb +134 -0
  41. data/templates/index.erb +24 -0
  42. data/templates/monthly_graph.erb +41 -0
  43. data/test/test_aggregation.rb +161 -0
  44. data/test/test_aggregation_methods.rb +50 -0
  45. data/test/test_base.rb +83 -0
  46. data/test/test_data.rb +118 -0
  47. data/test/test_model.rb +142 -0
  48. data/test/test_sync.rb +71 -0
  49. data/test/test_web.rb +87 -0
  50. metadata +167 -0
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @author Remy Sharp
3
+ * @date 2008-02-25
4
+ * @url http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/
5
+ * @license Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
6
+ */
7
+
8
+
9
+ (function ($) {
10
+ $.fn.selectChain = function (options, dynamic_data) {
11
+ var defaults = {
12
+ key: "id",
13
+ value: "label"
14
+ };
15
+
16
+ var settings = $.extend({}, defaults, options);
17
+
18
+ if (!(settings.target instanceof $)) settings.target = $(settings.target);
19
+
20
+
21
+ return this.each(function () {
22
+ var $$ = $(this);
23
+
24
+ $$.change(function () {
25
+ var data = null;
26
+ if (dynamic_data != null) {
27
+ dynamic_data(settings);
28
+ }
29
+
30
+ settings.target.empty();
31
+
32
+ $.ajax({
33
+ url: settings.url,
34
+ data: data,
35
+ type: (settings.type || 'get'),
36
+ dataType: 'json',
37
+ success: function (j) {
38
+ var options = [], i = 0, o = null;
39
+
40
+ for (i = 0; i < j.length; i++) {
41
+ // required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228)
42
+ o = document.createElement("OPTION");
43
+ o.value = typeof j[i] == 'object' ? j[i][settings.key] : j[i];
44
+ o.text = typeof j[i] == 'object' ? j[i][settings.value] : j[i];
45
+ settings.target.get(0).options[i] = o;
46
+ }
47
+
48
+ // hand control back to browser for a moment
49
+ setTimeout(function () {
50
+ settings.target
51
+ .find('option:l')
52
+ .attr('selected', 'selected')
53
+ .parent('select')
54
+ .trigger('change');
55
+ }, 0);
56
+ },
57
+ error: function (xhr, desc, er) {
58
+ // add whatever debug you want here.
59
+ alert("an error occurred");
60
+ }
61
+ });
62
+ });
63
+ });
64
+ };
65
+ $.fn.selectedOption = function()
66
+ {
67
+ var result = 0;
68
+ var sels = $(this).each( function() { result = this.options[this.selectedIndex].value});
69
+ return result;
70
+ }
71
+ })(jQuery);
@@ -0,0 +1,285 @@
1
+ /**
2
+ * tools.tabs 1.0.4 - Tabs done right.
3
+ *
4
+ * Copyright (c) 2009 Tero Piirainen
5
+ * http://flowplayer.org/tools/tabs.html
6
+ *
7
+ * Dual licensed under MIT and GPL 2+ licenses
8
+ * http://www.opensource.org/licenses
9
+ *
10
+ * Launch : November 2008
11
+ * Date: ${date}
12
+ * Revision: ${revision}
13
+ */
14
+ (function($) {
15
+
16
+ // static constructs
17
+ $.tools = $.tools || {};
18
+
19
+ $.tools.tabs = {
20
+ version: '1.0.4',
21
+
22
+ conf: {
23
+ tabs: 'a',
24
+ current: 'current',
25
+ onBeforeClick: null,
26
+ onClick: null,
27
+ effect: 'default',
28
+ initialIndex: 0,
29
+ event: 'click',
30
+ api:false,
31
+ rotate: false
32
+ },
33
+
34
+ addEffect: function(name, fn) {
35
+ effects[name] = fn;
36
+ }
37
+ };
38
+
39
+
40
+ var effects = {
41
+
42
+ // simple "toggle" effect
43
+ 'default': function(i, done) {
44
+ this.getPanes().hide().eq(i).show();
45
+ done.call();
46
+ },
47
+
48
+ /*
49
+ configuration:
50
+ - fadeOutSpeed (positive value does "crossfading")
51
+ - fadeInSpeed
52
+ */
53
+ fade: function(i, done) {
54
+ var conf = this.getConf(),
55
+ speed = conf.fadeOutSpeed,
56
+ panes = this.getPanes();
57
+
58
+ if (speed) {
59
+ panes.fadeOut(speed);
60
+ } else {
61
+ panes.hide();
62
+ }
63
+
64
+ panes.eq(i).fadeIn(conf.fadeInSpeed, done);
65
+ },
66
+
67
+ // for basic accordions
68
+ slide: function(i, done) {
69
+ this.getPanes().slideUp(200);
70
+ this.getPanes().eq(i).slideDown(400, done);
71
+ },
72
+
73
+ // simple AJAX effect
74
+ ajax: function(i, done) {
75
+ this.getPanes().eq(0).load(this.getTabs().eq(i).attr("href"), done);
76
+ }
77
+
78
+ };
79
+
80
+ var w;
81
+
82
+ // this is how you add effects
83
+ $.tools.tabs.addEffect("horizontal", function(i, done) {
84
+
85
+ // store original width of a pane into memory
86
+ if (!w) { w = this.getPanes().eq(0).width(); }
87
+
88
+ // set current pane's width to zero
89
+ this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); });
90
+
91
+ // grow opened pane to it's original width
92
+ this.getPanes().eq(i).animate({width: w}, function() {
93
+ $(this).show();
94
+ done.call();
95
+ });
96
+
97
+ });
98
+
99
+
100
+ function Tabs(tabs, panes, conf) {
101
+
102
+ var self = this, $self = $(this), current;
103
+
104
+ // bind all callbacks from configuration
105
+ $.each(conf, function(name, fn) {
106
+ if ($.isFunction(fn)) { $self.bind(name, fn); }
107
+ });
108
+
109
+
110
+ // public methods
111
+ $.extend(this, {
112
+ click: function(i, e) {
113
+
114
+ var pane = self.getCurrentPane();
115
+ var tab = tabs.eq(i);
116
+
117
+ if (typeof i == 'string' && i.replace("#", "")) {
118
+ tab = tabs.filter("[href*=" + i.replace("#", "") + "]");
119
+ i = Math.max(tabs.index(tab), 0);
120
+ }
121
+
122
+ if (conf.rotate) {
123
+ var last = tabs.length -1;
124
+ if (i < 0) { return self.click(last, e); }
125
+ if (i > last) { return self.click(0, e); }
126
+ }
127
+
128
+ if (!tab.length) {
129
+ if (current >= 0) { return self; }
130
+ i = conf.initialIndex;
131
+ tab = tabs.eq(i);
132
+ }
133
+
134
+ // current tab is being clicked
135
+ if (i === current) { return self; }
136
+
137
+ // possibility to cancel click action
138
+ e = e || $.Event();
139
+ e.type = "onBeforeClick";
140
+ $self.trigger(e, [i]);
141
+ if (e.isDefaultPrevented()) { return; }
142
+
143
+ // call the effect
144
+ effects[conf.effect].call(self, i, function() {
145
+
146
+ // onClick callback
147
+ e.type = "onClick";
148
+ $self.trigger(e, [i]);
149
+ });
150
+
151
+ // onStart
152
+ e.type = "onStart";
153
+ $self.trigger(e, [i]);
154
+ if (e.isDefaultPrevented()) { return; }
155
+
156
+ // default behaviour
157
+ current = i;
158
+ tabs.removeClass(conf.current);
159
+ tab.addClass(conf.current);
160
+
161
+ return self;
162
+ },
163
+
164
+ getConf: function() {
165
+ return conf;
166
+ },
167
+
168
+ getTabs: function() {
169
+ return tabs;
170
+ },
171
+
172
+ getPanes: function() {
173
+ return panes;
174
+ },
175
+
176
+ getCurrentPane: function() {
177
+ return panes.eq(current);
178
+ },
179
+
180
+ getCurrentTab: function() {
181
+ return tabs.eq(current);
182
+ },
183
+
184
+ getIndex: function() {
185
+ return current;
186
+ },
187
+
188
+ next: function() {
189
+ return self.click(current + 1);
190
+ },
191
+
192
+ prev: function() {
193
+ return self.click(current - 1);
194
+ },
195
+
196
+ bind: function(name, fn) {
197
+ $self.bind(name, fn);
198
+ return self;
199
+ },
200
+
201
+ onBeforeClick: function(fn) {
202
+ return this.bind("onBeforeClick", fn);
203
+ },
204
+
205
+ onClick: function(fn) {
206
+ return this.bind("onClick", fn);
207
+ },
208
+
209
+ unbind: function(name) {
210
+ $self.unbind(name);
211
+ return self;
212
+ }
213
+
214
+ });
215
+
216
+
217
+ // setup click actions for each tab
218
+ tabs.each(function(i) {
219
+ $(this).bind(conf.event, function(e) {
220
+ self.click(i, e);
221
+ return false;
222
+ });
223
+ });
224
+
225
+ // if no pane is visible --> click on the first tab
226
+ if (location.hash) {
227
+ self.click(location.hash);
228
+ } else {
229
+ if (conf.initialIndex === 0 || conf.initialIndex > 0) {
230
+ self.click(conf.initialIndex);
231
+ }
232
+ }
233
+
234
+ // cross tab anchor link
235
+ panes.find("a[href^=#]").click(function(e) {
236
+ self.click($(this).attr("href"), e);
237
+ });
238
+ }
239
+
240
+
241
+ // jQuery plugin implementation
242
+ $.fn.tabs = function(query, conf) {
243
+
244
+ // return existing instance
245
+ var el = this.eq(typeof conf == 'number' ? conf : 0).data("tabs");
246
+ if (el) { return el; }
247
+
248
+ if ($.isFunction(conf)) {
249
+ conf = {onBeforeClick: conf};
250
+ }
251
+
252
+ // setup options
253
+ var globals = $.extend({}, $.tools.tabs.conf), len = this.length;
254
+ conf = $.extend(globals, conf);
255
+
256
+
257
+ // install tabs for each items in jQuery
258
+ this.each(function(i) {
259
+ var root = $(this);
260
+
261
+ // find tabs
262
+ var els = root.find(conf.tabs);
263
+
264
+ if (!els.length) {
265
+ els = root.children();
266
+ }
267
+
268
+ // find panes
269
+ var panes = query.jquery ? query : root.children(query);
270
+
271
+ if (!panes.length) {
272
+ panes = len == 1 ? $(query) : root.parent().find(query);
273
+ }
274
+
275
+ el = new Tabs(els, panes, conf);
276
+ root.data("tabs", el);
277
+
278
+ });
279
+
280
+ return conf.api ? el: this;
281
+ };
282
+
283
+ }) (jQuery);
284
+
285
+
@@ -0,0 +1,87 @@
1
+ /* root element for tabs */
2
+ ul.tabs {
3
+ list-style:none;
4
+ margin:0 !important;
5
+ padding:0;
6
+ border-bottom:1px solid #666;
7
+ height:30px;
8
+ }
9
+
10
+ /* single tab */
11
+ ul.tabs li {
12
+ float:left;
13
+ text-indent:0;
14
+ padding:0;
15
+ margin:0 !important;
16
+ list-style-image:none !important;
17
+ }
18
+
19
+ /* link inside the tab. uses a background image */
20
+ ul.tabs a {
21
+ background: url(images/tabs.png) no-repeat -420px 0;
22
+ font-size:11px;
23
+ display:block;
24
+ height: 30px;
25
+ line-height:30px;
26
+ width: 134px;
27
+ text-align:center;
28
+ text-decoration:none;
29
+ color:#333;
30
+ padding:0px;
31
+ margin:0px;
32
+ position:relative;
33
+ top:1px;
34
+ }
35
+
36
+ ul.tabs a:active {
37
+ outline:none;
38
+ }
39
+
40
+ /* when mouse enters the tab move the background image */
41
+ ul.tabs a:hover {
42
+ background-position: -420px -31px;
43
+ color:#fff;
44
+ }
45
+
46
+ /* active tab uses a class name "current". it's highlight is also done by moving the background image. */
47
+ ul.tabs a.current, ul.tabs a.current:hover, ul.tabs li.current a {
48
+ background-position: -420px -62px;
49
+ cursor:default !important;
50
+ color:#000 !important;
51
+ }
52
+
53
+ /* Different widths for tabs: use a class name: w1, w2, w3 or w2 */
54
+
55
+
56
+ /* width 1 */
57
+ ul.tabs a.s { background-position: -553px 0; width:81px; }
58
+ ul.tabs a.s:hover { background-position: -553px -31px; }
59
+ ul.tabs a.s.current { background-position: -553px -62px; }
60
+
61
+ /* width 2 */
62
+ ul.tabs a.l { background-position: -248px -0px; width:174px; }
63
+ ul.tabs a.l:hover { background-position: -248px -31px; }
64
+ ul.tabs a.l.current { background-position: -248px -62px; }
65
+
66
+
67
+ /* width 3 */
68
+ ul.tabs a.xl { background-position: 0 -0px; width:248px; }
69
+ ul.tabs a.xl:hover { background-position: 0 -31px; }
70
+ ul.tabs a.xl.current { background-position: 0 -62px; }
71
+
72
+
73
+ /* initially all panes are hidden */
74
+ div.panes div.pane {
75
+ display:none;
76
+ }
77
+
78
+
79
+ div.panes > div {
80
+ padding:15px 10px;
81
+ border:1px solid #999;
82
+ border-top:0px;
83
+ font-size:14px;
84
+ background-color:#fff;
85
+ }
86
+
87
+
@@ -0,0 +1,31 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+ require 'rubygems'
3
+ require 'plantwatchdog/model'
4
+ require 'active_record'
5
+ require 'active_record/fixtures'
6
+
7
+ module PlantWatchdog
8
+ class CreateSolar
9
+ def CreateSolar.create
10
+ PlantWatchdog::Model::Schema.migrate(:up) unless ActiveRecord::Base.connection.table_exists? :users
11
+
12
+ fixture_path = File.join(File.dirname(__FILE__),"static")
13
+ p "Reading fixtures from #{fixture_path}"
14
+
15
+ table_names = Dir["#{fixture_path}/*.yml"].map! { |f| File.basename(f).split('.').first.to_s }
16
+ p "Found content for tables ", table_names.join(" ")
17
+ class_names = table_names.inject({ :metadata => "PlantWatchdog::Model::Metadata"}) {
18
+ |result, table_name|
19
+ key= table_name.to_sym
20
+ result[key] = "PlantWatchdog::Model::" + table_name.singularize.capitalize unless result[key]
21
+ result
22
+ }
23
+
24
+ fs = Fixtures.create_fixtures(fixture_path, table_names, class_names)
25
+ end
26
+ end
27
+ end
28
+
29
+ #user = PlantWatchdog::Model::User.find(:all).first
30
+ #p user.plant.aggrules
31
+ #p user.plant.devices.first.aggrules