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.
- 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
|