plantwatchdog 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/License.txt +674 -0
- data/Manifest.txt +42 -0
- data/README.txt +91 -0
- data/Rakefile +22 -0
- data/bin/plantwatchdog +8 -0
- data/bin/upload_measurements +2 -0
- data/config.ru +35 -0
- data/config/app_config.yaml +10 -0
- data/lib/plantwatchdog/aggregation.rb +220 -0
- data/lib/plantwatchdog/aggregation_methods.rb +90 -0
- data/lib/plantwatchdog/data.rb +126 -0
- data/lib/plantwatchdog/db.rb +37 -0
- data/lib/plantwatchdog/gems.rb +5 -0
- data/lib/plantwatchdog/main.rb +76 -0
- data/lib/plantwatchdog/model.rb +442 -0
- data/lib/plantwatchdog/sinatra.rb +206 -0
- data/public/images/arrow-down.gif +0 -0
- data/public/images/arrow-left.gif +0 -0
- data/public/images/arrow-right.gif +0 -0
- data/public/images/arrow-up.gif +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/images/tabs.png +0 -0
- data/public/js/customflot.js +120 -0
- data/public/js/jquery-1.3.2.min.js +19 -0
- data/public/js/jquery.flot.crosshair.js +157 -0
- data/public/js/jquery.flot.js +2119 -0
- data/public/js/jquery.flot.navigate.js +272 -0
- data/public/js/jquery.flot.selection.js +299 -0
- data/public/js/select-chain.js +71 -0
- data/public/js/tools.tabs-1.0.4.js +285 -0
- data/public/tabs.css +87 -0
- data/sample/solar/create_solar.rb +31 -0
- data/sample/solar/measurements/client.sqlite3 +0 -0
- data/sample/solar/static/devices.yml +17 -0
- data/sample/solar/static/metadata.yml +30 -0
- data/sample/solar/static/plants.yml +3 -0
- data/sample/solar/static/users.yml +4 -0
- data/sample/solar/upload_measurements +26 -0
- data/templates/graph.erb +134 -0
- data/templates/index.erb +24 -0
- data/templates/monthly_graph.erb +41 -0
- data/test/test_aggregation.rb +161 -0
- data/test/test_aggregation_methods.rb +50 -0
- data/test/test_base.rb +83 -0
- data/test/test_data.rb +118 -0
- data/test/test_model.rb +142 -0
- data/test/test_sync.rb +71 -0
- data/test/test_web.rb +87 -0
- metadata +167 -0
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
inverter1:
|
2
|
+
plant: default_plant
|
3
|
+
unique_id: "2100147669"
|
4
|
+
metadata: inverter_meta
|
5
|
+
aggregationrule: inverter_aggrules
|
6
|
+
|
7
|
+
inverter2:
|
8
|
+
plant: default_plant
|
9
|
+
unique_id: "2100147715"
|
10
|
+
metadata: inverter_meta
|
11
|
+
aggregationrule: inverter_aggrules
|
12
|
+
|
13
|
+
sunmeter:
|
14
|
+
plant: default_plant
|
15
|
+
unique_id: "sunmeter"
|
16
|
+
metadata: sunmeter_meta
|
17
|
+
aggregationrule: sunmeter_aggrules
|
@@ -0,0 +1,30 @@
|
|
1
|
+
plant_aggrules:
|
2
|
+
description: '{
|
3
|
+
eday : [sum, eday],
|
4
|
+
pac : [sum, pac],
|
5
|
+
irradiance : [pick, 0, irradiance],
|
6
|
+
temperature : [pick, 0, temperature],
|
7
|
+
inv0_eday : [pick, 1, eday],
|
8
|
+
inv1_eday : [pick, 2, eday]
|
9
|
+
}'
|
10
|
+
|
11
|
+
inverter_meta:
|
12
|
+
description: '[[time, integer], [pac, float], [etotal, float]]'
|
13
|
+
|
14
|
+
# pac is W, integrated W*sec, divide by 3600 to get W*h, divide by 1000 to get kw*h
|
15
|
+
inverter_aggrules:
|
16
|
+
description: '{
|
17
|
+
eday : [growth, etotal],
|
18
|
+
pac : [div, [integrate, time, pac], 3600000]
|
19
|
+
}'
|
20
|
+
|
21
|
+
sunmeter_meta:
|
22
|
+
description: '[[time, integer], [irradiance, float], [temperature, integer]]'
|
23
|
+
|
24
|
+
# irradiance is W/qm, integrated W/qm*sec, divide by 3600 to get W/qm*h, multiply by 80qm to get W*h, divide by 1000 to get kw*h
|
25
|
+
# 1/10th => Umsetzung
|
26
|
+
sunmeter_aggrules:
|
27
|
+
description: '{
|
28
|
+
irradiance : [mult, 80, [div, [integrate, time, irradiance], 36000000]],
|
29
|
+
temperature : [avg, temperature]
|
30
|
+
}'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# this script uploads measurement data to a plant watchdog server
|
3
|
+
# To prepare the server you can run
|
4
|
+
# $ plantwatchdog --create_solar
|
5
|
+
# which creates an appropriate schema.
|
6
|
+
# Then start the server and run this script with the approriate host and port
|
7
|
+
host=${1:-127.0.0.1}
|
8
|
+
port=${2:-7000}
|
9
|
+
client_db=${3:-`dirname "$0"`/measurements/client.sqlite3}
|
10
|
+
csv_file=/tmp/measurements.csv
|
11
|
+
baseurl=http://$host:$port
|
12
|
+
user=markus
|
13
|
+
pw=markus
|
14
|
+
echo Upload measurements from $client_db to plant watchdog at $baseurl using $user:$pw
|
15
|
+
|
16
|
+
ids=`sqlite3 $client_db "select distinct inverterid from inverters"`
|
17
|
+
sqlite3 -csv $client_db 'select time, irradiance, temperature from environment' > $csv_file
|
18
|
+
count=`curl --user $user:$pw -T $csv_file $baseurl/upload/device/sunmeter`
|
19
|
+
echo Uploaded $count sunmeter measurements
|
20
|
+
for id in $ids
|
21
|
+
do
|
22
|
+
sqlite3 -csv $client_db "select time, pac, etotal from inverters where inverterid=$id" > $csv_file
|
23
|
+
count=`curl --user $user:$pw -T $csv_file $baseurl/upload/device/$id`
|
24
|
+
echo Uploaded $count measurements of inverter $id
|
25
|
+
done
|
26
|
+
rm $csv_file
|
data/templates/graph.erb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
<style>
|
2
|
+
#placeholder .button {
|
3
|
+
position: absolute;
|
4
|
+
cursor: pointer;
|
5
|
+
}
|
6
|
+
#placeholder div.button {
|
7
|
+
font-size: smaller;
|
8
|
+
color: #999;
|
9
|
+
background-color: #eee;
|
10
|
+
padding: 2px;
|
11
|
+
}
|
12
|
+
.loading {
|
13
|
+
background: url(/images/spinner.gif) no-repeat center center;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
<link rel="stylesheet" href="tabs.css" type="text/css" />
|
17
|
+
<ul class="tabs">
|
18
|
+
<li><a href="#"><span>Intraday</span></a></li>
|
19
|
+
<li><a href="#"><span>Monthly report</span></a></li>
|
20
|
+
</ul>
|
21
|
+
<div class="panes">
|
22
|
+
<div id="intraday">
|
23
|
+
<form id="graph_form">
|
24
|
+
<label for="select_graph_year">Year:</label></td>
|
25
|
+
<select name="year" size="1" id="select_graph_year">
|
26
|
+
<% years = years_with_data(user);
|
27
|
+
years.each_index {
|
28
|
+
|i| %>
|
29
|
+
<option <%=i == years.size() -1 ? 'selected="selected"' : ""%>><%=years[i].to_s%></option>
|
30
|
+
<% } %>
|
31
|
+
</select>
|
32
|
+
<label for="select_graph_month">Month:</label></td>
|
33
|
+
<select name="month" size="1" id="select_graph_month">
|
34
|
+
</select>
|
35
|
+
<label for="select_graph_day">Day:</label></td>
|
36
|
+
<select name="day" size="1" id="select_graph_day">
|
37
|
+
</select>
|
38
|
+
|
39
|
+
<input class="fetchSeries" type="submit" value="Draw">
|
40
|
+
<br></br>
|
41
|
+
<!-- TODO: this is the view definition. It should not take place here but should be
|
42
|
+
generated from a view definition DSL from ruby -->
|
43
|
+
<input type="radio" name="radio_type" value="0" id="intraday_graph_type_inverter" checked="checked"/>
|
44
|
+
<label for="intraday_graph_type_inverter">Inverter</label>
|
45
|
+
<input type="radio" name="radio_type" value="1" id="intraday_graph_type_environment"/>
|
46
|
+
<label for="intraday_graph_type_environment">Environment</label>
|
47
|
+
|
48
|
+
</form>
|
49
|
+
<div id="placeholder" style="width:<%=graph_width%>;height:<%=graph_height%>;"></div>
|
50
|
+
</div>
|
51
|
+
<div id="graph_monthly">
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
|
55
|
+
<script src="/js/jquery-1.3.2.min.js" type="text/javascript"></script>
|
56
|
+
<script id="source" language="javascript" type="text/javascript">
|
57
|
+
prepare_graph = function () {
|
58
|
+
var year = $('#select_graph_year');
|
59
|
+
var month = $('#select_graph_month');
|
60
|
+
var day = $('#select_graph_day');
|
61
|
+
month.selectChain({
|
62
|
+
target: day,
|
63
|
+
type: 'get',
|
64
|
+
data: { }
|
65
|
+
},
|
66
|
+
function(settings) { settings.url = '/availabledata/'+$('#select_graph_year').selectedOption() + '/' + $('#select_graph_month').selectedOption() ;}
|
67
|
+
);
|
68
|
+
|
69
|
+
// note that we're assigning in reverse order
|
70
|
+
// to allow the chaining change trigger to work
|
71
|
+
year.selectChain({
|
72
|
+
target: month,
|
73
|
+
type: 'get',
|
74
|
+
data: {}
|
75
|
+
},
|
76
|
+
function(settings) { settings.url = '/availabledata/'+$('#select_graph_year').selectedOption();}
|
77
|
+
).trigger('change');
|
78
|
+
day.change(function() {
|
79
|
+
if (month.get(0).options.selectedIndex >= 0) {
|
80
|
+
$('#graph_form:first').submit();
|
81
|
+
}
|
82
|
+
}) ;
|
83
|
+
|
84
|
+
|
85
|
+
var intraday = new Graph("#placeholder");
|
86
|
+
intraday.urlfunction = function() { return '/rawdata/' + $('#select_graph_year').selectedOption() + '/' + $('#select_graph_month').selectedOption() + '/' + $('#select_graph_day').selectedOption() };
|
87
|
+
$("form#graph_form").submit(function() { return intraday.submitForm() } );
|
88
|
+
|
89
|
+
// TODO: move view definition to ruby
|
90
|
+
// provide two views on the same data set
|
91
|
+
var set_intraday_filter=function()
|
92
|
+
{
|
93
|
+
if ($("input[@name='radio_type']:checked").val()==0)
|
94
|
+
intraday.seriesFilter=function(series) { return series["label"].indexOf("temperature") == -1; }
|
95
|
+
else
|
96
|
+
intraday.seriesFilter=function(series) { return series["label"].match("temperature|irradiance") != null; }
|
97
|
+
}
|
98
|
+
set_intraday_filter();
|
99
|
+
$("form#graph_form input:radio").click(function() { set_intraday_filter(); intraday.customPlot(); });
|
100
|
+
|
101
|
+
// Tabs
|
102
|
+
var api = $("ul.tabs").tabs("div.panes > div");
|
103
|
+
api = $("ul.tabs").tabs();
|
104
|
+
api.onClick(function(event, index) {
|
105
|
+
if (index==1) {
|
106
|
+
$.ajax( { url: "monthly_graph.html?width="+intraday.placeholder.css("width")+"&height=" + intraday.placeholder.css("height"),
|
107
|
+
context: document.body,
|
108
|
+
success: function(data, textStatus, XMLHttpRequest) {
|
109
|
+
$("#graph_monthly").html(data);
|
110
|
+
}
|
111
|
+
} );
|
112
|
+
} else {
|
113
|
+
|
114
|
+
}
|
115
|
+
});
|
116
|
+
};
|
117
|
+
|
118
|
+
var scripts = [ "js/select-chain.js", "js/jquery.flot.crosshair.js", "js/jquery.flot.selection.js",
|
119
|
+
"js/jquery.flot.navigate.js", "js/tools.tabs-1.0.4.js", "js/customflot.js" ]
|
120
|
+
var loaded = 0;
|
121
|
+
function load_other_scripts() {
|
122
|
+
$.each( scripts,
|
123
|
+
function(i,script) {
|
124
|
+
$.getScript(script, function() {
|
125
|
+
loaded += 1;
|
126
|
+
if (loaded == scripts.length) {
|
127
|
+
prepare_graph();
|
128
|
+
}
|
129
|
+
});
|
130
|
+
});
|
131
|
+
};
|
132
|
+
// make sure that flot is loaded before the other scripts, since some of them depend on it
|
133
|
+
$.getScript("js/jquery.flot.js", function() { load_other_scripts() });
|
134
|
+
</script>
|
data/templates/index.erb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
|
5
|
+
<title>Plant Watchdog</title>
|
6
|
+
</head>
|
7
|
+
<style>
|
8
|
+
#placeholder {
|
9
|
+
width: 350px;
|
10
|
+
height: 600px;
|
11
|
+
}
|
12
|
+
|
13
|
+
.loading {
|
14
|
+
background: url(/images/spinner.gif) no-repeat center center;
|
15
|
+
}
|
16
|
+
</style>
|
17
|
+
<body>
|
18
|
+
|
19
|
+
<iframe allowtransparency="true" id="plantwatchdog" name="plantwatchdog"
|
20
|
+
scrolling="no" frameborder="1" border="1"
|
21
|
+
style="border:1; width:400px;height:340px;margin:0;padding:0;"
|
22
|
+
src="graph.html?height=200px&width=320px"></iframe>
|
23
|
+
</body>
|
24
|
+
</html>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<form id="monthly_graph_form">
|
2
|
+
<label for="monthly_graph_year">Jahr:</label></td>
|
3
|
+
<select name="year" size="1" id="monthly_graph_year">
|
4
|
+
<% years = years_with_data(user);
|
5
|
+
years.each_index {
|
6
|
+
|i| %>
|
7
|
+
<option <%=i == years.size() -1 ? 'selected="selected"' : ""%>><%=years[i].to_s%></option>
|
8
|
+
<% } %>
|
9
|
+
</select>
|
10
|
+
<label for="monthly_graph_month">Monat:</label></td>
|
11
|
+
<select name="month" size="1" id="monthly_graph_month">
|
12
|
+
</select>
|
13
|
+
|
14
|
+
<input class="fetchSeries" type="submit" value="Zeichnen">
|
15
|
+
|
16
|
+
</form>
|
17
|
+
<div id="monthly_placeholder" style="width:<%=graph_width%>;height:<%=graph_height%>;"></div>
|
18
|
+
|
19
|
+
<script id="source" language="javascript" type="text/javascript">
|
20
|
+
$(function () {
|
21
|
+
var year = $('#monthly_graph_year');
|
22
|
+
var month = $('#monthly_graph_month');
|
23
|
+
year.selectChain({
|
24
|
+
target: month,
|
25
|
+
type: 'get',
|
26
|
+
data: {}
|
27
|
+
},
|
28
|
+
function(settings) { settings.url = '/availabledata/'+$('#monthly_graph_year').selectedOption();}
|
29
|
+
).trigger('change');
|
30
|
+
month.change(function() {
|
31
|
+
if (year.get(0).options.selectedIndex >= 0) {
|
32
|
+
$('#monthly_graph_form:first').submit();
|
33
|
+
}
|
34
|
+
}) ;
|
35
|
+
});
|
36
|
+
|
37
|
+
var monthly = new Graph("#monthly_placeholder");
|
38
|
+
monthly.urlfunction = function() { return '/monthly/plant/' + $('#monthly_graph_year').selectedOption() + '/' + $('#monthly_graph_month').selectedOption() }
|
39
|
+
$("form#monthly_graph_form").submit(function() { return monthly.submitForm() } );
|
40
|
+
|
41
|
+
</script>
|
@@ -0,0 +1,161 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__),"..")
|
3
|
+
require 'rubygems'
|
4
|
+
require 'plantwatchdog/model'
|
5
|
+
require 'plantwatchdog/aggregation'
|
6
|
+
require 'test/unit'
|
7
|
+
require 'test/test_base'
|
8
|
+
|
9
|
+
module PlantWatchdog
|
10
|
+
class ModelTest < Test::Unit::TestCase
|
11
|
+
include TestUtil
|
12
|
+
def test_device_aggregation
|
13
|
+
# make sure that the aggregation Methods are called correctly
|
14
|
+
# device
|
15
|
+
year = 2010
|
16
|
+
day = 50
|
17
|
+
plant = Model::Plant.new
|
18
|
+
|
19
|
+
inv_aggrules = { "agg1" => [:aggZeroParam], "agg2" => [:aggOneParam, :time], "agg3" => [:aggTwoParams, :time, :pac] }
|
20
|
+
inv_meta = [["time", "integer"], ["pac", "integer"]]
|
21
|
+
inverter1 = Model::Device.new
|
22
|
+
inverter1.aggrules = inv_aggrules
|
23
|
+
inverter1.plant = plant
|
24
|
+
inverter1.meta = inv_meta
|
25
|
+
inverter1.save!
|
26
|
+
|
27
|
+
invMeasurement = Model::MeasurementChunk.new()
|
28
|
+
invMeasurement.time_year = year
|
29
|
+
invMeasurement.time_day_of_year = day
|
30
|
+
invMeasurement.meta = inv_meta # TODO set automatically
|
31
|
+
invMeasurement.data = <<EOF
|
32
|
+
12,33
|
33
|
+
16,0
|
34
|
+
EOF
|
35
|
+
invMeasurement.device = inverter1
|
36
|
+
invMeasurement.save!
|
37
|
+
|
38
|
+
calledZeroParam = nil
|
39
|
+
calledOneParam = nil
|
40
|
+
calledTwoParams = nil
|
41
|
+
|
42
|
+
Aggregation::Methods.class.send(:define_method, :aggZeroParam, Proc.new { calledZeroParam = true })
|
43
|
+
Aggregation::Methods.class.send(:define_method, :aggOneParam, Proc.new { |p1| calledOneParam = p1 })
|
44
|
+
Aggregation::Methods.class.send(:define_method, :aggTwoParams, Proc.new { |p1,p2| calledTwoParams = [p1,p2] })
|
45
|
+
|
46
|
+
aggDevice = Aggregation::Device.create(inverter1, year, day)
|
47
|
+
aggDevice.aggregate
|
48
|
+
|
49
|
+
assert_equal(true, calledZeroParam)
|
50
|
+
assert_equal([12,16], calledOneParam)
|
51
|
+
assert_equal([[12,16], [33,0]], calledTwoParams)
|
52
|
+
|
53
|
+
Aggregation::Methods.class.send(:define_method, :nested, Proc.new { |t| t.first + t.last })
|
54
|
+
inverter1.aggrules = { "nested" => [:mult, 0.5, [:nested, :time]] }
|
55
|
+
device_aggregate = aggDevice.aggregate()
|
56
|
+
assert_equal(14, device_aggregate["nested"])
|
57
|
+
|
58
|
+
plant.aggrules = { "picked" => [ :pick, 0, :nested] }
|
59
|
+
plant.save!
|
60
|
+
|
61
|
+
aggPlant = Aggregation::Plant.new(plant, [ device_aggregate ])
|
62
|
+
assert_equal(14, aggPlant.aggregate()["picked"])
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_aggregation
|
66
|
+
year = 2010
|
67
|
+
day = 50
|
68
|
+
plant = Model::Plant.new
|
69
|
+
plant.aggrules = { "eday" => [:sum, "eday"] }
|
70
|
+
plant.save
|
71
|
+
|
72
|
+
sunmeter = Model::Device.new
|
73
|
+
sunmeter.aggrules = { :avg_temperature => [:avg, :temperature], "irradiance" => [:integrate, :time, :irradiance] }
|
74
|
+
sunmeter.plant = plant
|
75
|
+
sunmeter.meta = [["time", "integer"], ["temperature", "integer"], ["irradiance", "integer"]]
|
76
|
+
sunmeter.save!
|
77
|
+
|
78
|
+
envMeasurement = Model::MeasurementChunk.new()
|
79
|
+
envMeasurement.time_year = year
|
80
|
+
envMeasurement.time_day_of_year = day
|
81
|
+
envMeasurement.data = <<EOF
|
82
|
+
12,32,500
|
83
|
+
15,30,480
|
84
|
+
EOF
|
85
|
+
envMeasurement.device = sunmeter
|
86
|
+
# TODO meta should be taken from sunmeter automatically
|
87
|
+
envMeasurement.meta = sunmeter.meta
|
88
|
+
envMeasurement.save!
|
89
|
+
|
90
|
+
# create two inverters with the same metadata
|
91
|
+
inv_aggrules = { "eday" => [:growth, :etotal], "pac" => [:integrate, :time, :pac], "expected" => [ :expected] }
|
92
|
+
inv_meta = [["time", "integer"], ["pac", "integer"], ["etotal", "float"]]
|
93
|
+
inverter1 = Model::Device.new
|
94
|
+
inverter1.aggrules = inv_aggrules
|
95
|
+
inverter1.plant = plant
|
96
|
+
inverter1.meta = inv_meta
|
97
|
+
inverter1.save!
|
98
|
+
|
99
|
+
invMeasurement = Model::MeasurementChunk.new()
|
100
|
+
invMeasurement.time_year = year
|
101
|
+
invMeasurement.time_day_of_year = day
|
102
|
+
invMeasurement.meta = inv_meta # TODO set automatically
|
103
|
+
invMeasurement.data = <<EOF
|
104
|
+
12,33,60.1
|
105
|
+
16,0,60.5
|
106
|
+
EOF
|
107
|
+
invMeasurement.device = inverter1
|
108
|
+
invMeasurement.save!
|
109
|
+
|
110
|
+
inverter2 = Model::Device.new
|
111
|
+
inverter2.aggrules = inv_aggrules
|
112
|
+
inverter2.plant = plant
|
113
|
+
inverter2.meta = inv_meta
|
114
|
+
inverter2.save!
|
115
|
+
|
116
|
+
invMeasurement = Model::MeasurementChunk.new()
|
117
|
+
invMeasurement.time_year = year
|
118
|
+
invMeasurement.time_day_of_year = day
|
119
|
+
invMeasurement.meta = inv_meta # TODO set automatically
|
120
|
+
invMeasurement.data = <<EOF
|
121
|
+
12,43,90.1
|
122
|
+
14,50,100.0
|
123
|
+
18,35,105.0
|
124
|
+
EOF
|
125
|
+
invMeasurement.device = inverter2
|
126
|
+
invMeasurement.save!
|
127
|
+
|
128
|
+
runner = Aggregation::Runner.new
|
129
|
+
agg_sunmeter, agg_inv1, agg_inv2, agg_plant = runner.aggregate(Model::Plant.find(:first), year, day)
|
130
|
+
assert_equal(31, agg_sunmeter.data["avg_temperature"])
|
131
|
+
eday_inv1 = 60.5 - 60.1 ; eday_inv2 = 105.0 - 90.1;
|
132
|
+
pac_inv1 = 4 * 33 / 2.0
|
133
|
+
assert_equal(eday_inv1, agg_inv1.data["eday"])
|
134
|
+
assert_equal(pac_inv1, agg_inv1.data["pac"])
|
135
|
+
assert_equal(eday_inv2, agg_inv2.data["eday"])
|
136
|
+
assert_equal(eday_inv1 + eday_inv2, agg_plant.data["eday"])
|
137
|
+
|
138
|
+
# check that daily aggregate entry was created in db
|
139
|
+
saved_plant_agg = Model::MeasurementAggregate.find(:first, :conditions => ["plant_id=?", plant.id])
|
140
|
+
assert_equal(year, saved_plant_agg.time_year)
|
141
|
+
assert_equal(day, saved_plant_agg.time_day_of_year)
|
142
|
+
assert(saved_plant_agg.data.keys.include?("eday"))
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_find_missing_aggregates
|
147
|
+
inverter = create_inverter
|
148
|
+
|
149
|
+
chunk = Model::MeasurementChunk.new()
|
150
|
+
chunk.time_year = 2222
|
151
|
+
chunk.time_day_of_year = 52
|
152
|
+
chunk.device = inverter
|
153
|
+
chunk.save!
|
154
|
+
|
155
|
+
runner = Aggregation::Runner.new
|
156
|
+
assert_equal([[chunk.time_year, chunk.time_day_of_year, inverter.plant.id]], runner.find_missing_aggregates)
|
157
|
+
runner.run
|
158
|
+
assert_equal([], runner.find_missing_aggregates)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|