Improving the dashboard and replaced inverter energy chart with site energy chart.
BrainDoctor committed
Jul 6, 2017 at 15:47 UTC
b25815c0a753516f73f7c288418b3a3a391d94b2
2 files changed
+108
-73
node.d/fronius.node.js
+79
-73
@@ -19,33 +19,34 @@ var fronius = {
19
charts: {},
20
21
powerGridId: "p_grid",
22
- powerPvId: 'p_pv',
23
- powerAccuId: 'p_akku', // not my typo! Using the ID from the AP
24
- consumptionLoadId: 'p_load',
25
- autonomyId: 'rel_autonomy',
26
- consumptionSelfId: 'rel_selfconsumption',
27
-
28
- createBasicDimension: function (id, name) {
22
+ powerPvId: "p_pv",
23
+ powerAccuId: "p_akku", // not my typo! Using the ID from the AP
24
+ consumptionLoadId: "p_load",
25
+ autonomyId: "rel_autonomy",
26
+ consumptionSelfId: "rel_selfconsumption",
27
+ energyTodayId: "e_day",
28
+ energyYearId: "e_year",
29
+
30
+ createBasicDimension: function (id, name, divisor) {
31
return {
32
id: id, // the unique id of the dimension
33
name: name, // the name of the dimension
34
algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
35
multiplier: 1, // the multiplier
34
- divisor: 1, // the divisor
36
+ divisor: divisor, // the divisor
37
hidden: false // is hidden (boolean)
38
};
39
},
40
41
// Gets the site power chart. Will be created if not existing.
42
getSitePowerChart: function (service, id) {
41
-
43
var chart = fronius.charts[id];
44
if (fronius.isDefined(chart)) return chart;
45
46
var dim = {};
46
- dim[fronius.powerGridId] = this.createBasicDimension(fronius.powerGridId, "Grid");
47
- dim[fronius.powerPvId] = this.createBasicDimension(fronius.powerPvId, "Photovoltaics");
48
- dim[fronius.powerAccuId] = this.createBasicDimension(fronius.powerAccuId, "Accumulator");
47
+ dim[fronius.powerGridId] = this.createBasicDimension(fronius.powerGridId, "Grid", 1);
48
+ dim[fronius.powerPvId] = this.createBasicDimension(fronius.powerPvId, "Photovoltaics", 1);
49
+ dim[fronius.powerAccuId] = this.createBasicDimension(fronius.powerAccuId, "Accumulator", 1);
50
51
chart = {
52
id: id, // the unique id of the chart
@@ -67,11 +68,10 @@ var fronius = {
68
69
// Gets the site consumption chart. Will be created if not existing.
70
getSiteConsumptionChart: function (service, id) {
70
-
71
var chart = fronius.charts[id];
72
if (fronius.isDefined(chart)) return chart;
73
var dim = {};
74
- dim[fronius.consumptionLoadId] = this.createBasicDimension(fronius.consumptionLoadId, "Load");
74
+ dim[fronius.consumptionLoadId] = this.createBasicDimension(fronius.consumptionLoadId, "Load", 1);
75
76
chart = {
77
id: id, // the unique id of the chart
@@ -91,14 +91,13 @@ var fronius = {
91
return chart;
92
},
93
94
-
94
// Gets the site consumption chart. Will be created if not existing.
95
getSiteAutonomyChart: function (service, id) {
96
var chart = fronius.charts[id];
97
if (fronius.isDefined(chart)) return chart;
98
var dim = {};
100
- dim[fronius.autonomyId] = this.createBasicDimension(fronius.autonomyId, "Autonomy");
101
- dim[fronius.consumptionSelfId] = this.createBasicDimension(fronius.consumptionSelfId, "Self Consumption");
99
+ dim[fronius.autonomyId] = this.createBasicDimension(fronius.autonomyId, "Autonomy", 1);
100
+ dim[fronius.consumptionSelfId] = this.createBasicDimension(fronius.consumptionSelfId, "Self Consumption", 1);
101
102
chart = {
103
id: id, // the unique id of the chart
@@ -118,36 +117,45 @@ var fronius = {
117
return chart;
118
},
119
121
- // Gets the inverter power chart. Will be created if not existing.
122
- // Needs the array of inverters in order to create a chart with all inverters as dimensions
123
- getInverterPowerChart: function (service, chartId, inverters) {
124
-
120
+ // Gets the site energy chart for today. Will be created if not existing.
121
+ getSiteEnergyTodayChart: function (service, chartId) {
122
var chart = fronius.charts[chartId];
123
if (fronius.isDefined(chart)) return chart;
127
-
124
var dim = {};
125
+ dim[fronius.energyTodayId] = this.createBasicDimension(fronius.energyTodayId, "Today", 1000);
126
+ chart = {
127
+ id: chartId, // the unique id of the chart
128
+ name: '', // the unique name of the chart
129
+ title: service.name + ' Energy production for today', // the title of the chart
130
+ units: 'kWh', // the units of the chart dimensions
131
+ family: 'Energy', // the family of the chart
132
+ context: 'fronius.energy.today', // the context of the chart
133
+ type: netdata.chartTypes.area, // the type of the chart
134
+ priority: fronius.base_priority + 4, // the priority relative to others in the same family
135
+ update_every: service.update_every, // the expected update frequency of the chart
136
+ dimensions: dim
137
+ };
138
+ chart = service.chart(chartId, chart);
139
+ fronius.charts[chartId] = chart;
140
130
- var inverterCount = Object.keys(inverters).length;
131
- var inverter = inverters[inverterCount.toString()];
132
- var i = 1;
133
- for (i; i <= inverterCount; i++) {
134
- if (fronius.isUndefined(inverter)) {
135
- netdata.error("Expected an Inverter with a numerical name! " +
136
- "Have a look at your JSON output to verify.");
137
- continue;
138
- }
139
- dim[i.toString()] = this.createBasicDimension("inverter_" + i, "Inverter " + i);
140
- }
141
+ return chart;
142
+ },
143
144
+ // Gets the site energy chart for today. Will be created if not existing.
145
+ getSiteEnergyYearChart: function (service, chartId) {
146
+ var chart = fronius.charts[chartId];
147
+ if (fronius.isDefined(chart)) return chart;
148
+ var dim = {};
149
+ dim[fronius.energyYearId] = this.createBasicDimension(fronius.energyYearId, "Year", 1000);
150
chart = {
151
id: chartId, // the unique id of the chart
152
name: '', // the unique name of the chart
145
- title: service.name + ' Current Inverter Output', // the title of the chart
146
- units: 'W', // the units of the chart dimensions
147
- family: 'Inverters', // the family of the chart
148
- context: 'fronius.inverter', // the context of the chart
149
- type: netdata.chartTypes.stacked, // the type of the chart
150
- priority: fronius.base_priority + 4, // the priority relative to others in the same family
153
+ title: service.name + ' Energy production for this year', // the title of the chart
154
+ units: 'kWh', // the units of the chart dimensions
155
+ family: 'Energy', // the family of the chart
156
+ context: 'fronius.energy.year', // the context of the chart
157
+ type: netdata.chartTypes.area, // the type of the chart
158
+ priority: fronius.base_priority + 5, // the priority relative to others in the same family
159
update_every: service.update_every, // the expected update frequency of the chart
160
dimensions: dim
161
};
@@ -157,9 +165,9 @@ var fronius = {
165
return chart;
166
},
167
160
- // Gets the inverter energy production chart for today. Will be created if not existing.
168
+ // Gets the inverter power chart. Will be created if not existing.
169
// Needs the array of inverters in order to create a chart with all inverters as dimensions
162
- getInverterEnergyTodayChart: function (service, chartId, inverters) {
170
+ getInverterPowerChart: function (service, chartId, inverters) {
171
172
var chart = fronius.charts[chartId];
173
if (fronius.isDefined(chart)) return chart;
@@ -175,25 +183,18 @@ var fronius = {
183
"Have a look at your JSON output to verify.");
184
continue;
185
}
178
- dim[i.toString()] = {
179
- id: 'inverter_' + i, // the unique id of the dimension
180
- name: 'Inverter ' + i, // the name of the dimension
181
- algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
182
- multiplier: 1, // the multiplier
183
- divisor: 1000, // the divisor
184
- hidden: false // is hidden (boolean)
185
- };
186
+ dim[i.toString()] = this.createBasicDimension("inverter_" + i, "Inverter " + i, 1);
187
}
188
189
chart = {
190
id: chartId, // the unique id of the chart
191
name: '', // the unique name of the chart
191
- title: service.name + ' Inverter Energy production for today', // the title of the chart
192
- units: 'kWh', // the units of the chart dimensions
192
+ title: service.name + ' Current Inverter Output', // the title of the chart
193
+ units: 'W', // the units of the chart dimensions
194
family: 'Inverters', // the family of the chart
194
- context: 'fronius.inverter', // the context of the chart
195
+ context: 'fronius.inverter.output', // the context of the chart
196
type: netdata.chartTypes.stacked, // the type of the chart
196
- priority: fronius.base_priority + 5, // the priority relative to others in the same family
197
+ priority: fronius.base_priority + 6, // the priority relative to others in the same family
198
update_every: service.update_every, // the expected update frequency of the chart
199
dimensions: dim
200
};
@@ -203,18 +204,13 @@ var fronius = {
204
return chart;
205
},
206
206
-
207
processResponse: function (service, content) {
208
if (content === null) return;
209
var json = JSON.parse(content);
210
- // validating response
211
- if (fronius.isUndefined(json.Body)) return;
212
- if (fronius.isUndefined(json.Body.Data)) return;
213
- if (fronius.isUndefined(json.Body.Data.Site)) return;
214
- if (fronius.isUndefined(json.Body.Data.Inverters)) return;
210
+ if (!fronius.isResponseValid(json)) return;
211
212
// add the service
217
- if (service.added !== true) service.commit();
213
+ service.commit();
214
215
var site = json.Body.Data.Site;
216
@@ -240,24 +236,37 @@ var fronius = {
236
service.set(fronius.consumptionSelfId, Math.round(site.rel_SelfConsumption));
237
service.end();
238
239
+ // Site Energy Today Chart
240
+ service.begin(fronius.getSiteEnergyTodayChart(service, 'fronius_' + service.name + '.energy.today'));
241
+ service.set(fronius.energyTodayId, Math.round(site.E_Day));
242
+ service.end();
243
+
244
+ // Site Energy Year Chart
245
+ service.begin(fronius.getSiteEnergyYearChart(service, 'fronius_' + service.name + '.energy.year'));
246
+ service.set(fronius.energyYearId, Math.round(site.E_Year));
247
+ service.end();
248
+
249
// Inverters
250
var inverters = json.Body.Data.Inverters;
245
- var inverterCount = Object.keys(inverters).length;
246
- if (inverterCount <= 0) return;
247
- var i = 1;
248
- for (i; i <= inverterCount; i++) {
249
- var inverter = inverters[i];
251
+ var inverterCount = Object.keys(inverters).length + 1;
252
+ while (inverterCount--) {
253
+ var inverter = inverters[inverterCount];
254
if (fronius.isUndefined(inverter)) continue;
251
- netdata.debug("Setting values");
255
service.begin(fronius.getInverterPowerChart(service, 'fronius_' + service.name + '.inverters.output', inverters));
253
- service.set(i.toString(), Math.round(inverter.P));
254
- service.end();
255
- service.begin(fronius.getInverterEnergyTodayChart(service, 'fronius_' + service.name + '.inverters.today', inverters));
256
- service.set(i.toString(), Math.round(inverter.E_Day));
256
+ service.set(inverterCount.toString(), Math.round(inverter.P));
257
service.end();
258
}
259
},
260
261
+ // some basic validation
262
+ isResponseValid: function (json) {
263
+ if (fronius.isUndefined(json.Body)) return false;
264
+ if (fronius.isUndefined(json.Body.Data)) return false;
265
+ if (fronius.isUndefined(json.Body.Data.Site)) return false;
266
+ if (fronius.isUndefined(json.Body.Data.Inverters)) return false;
267
+ return true;
268
+ },
269
+
270
// module.serviceExecute()
271
// this function is called only from this module
272
// its purpose is to prepare the request and call
@@ -271,7 +280,6 @@ var fronius = {
280
update_every: update_every,
281
module: this
282
});
274
- service.request.method = 'GET';
283
service.execute(this.processResponse);
284
},
285
@@ -308,8 +316,6 @@ var fronius = {
316
isDefined: function (value) {
317
return typeof value !== 'undefined';
318
}
311
-
312
-
319
};
320
321
module.exports = fronius;
web/dashboard_info.js
+29
@@ -285,6 +285,12 @@ netdataDashboard.menu = {
285
info: undefined
286
},
287
288
+ 'fronius': {
289
+ title: 'Solar Power',
290
+ icon: '<i class="fa fa-sun-o" aria-hidden="true"></i>',
291
+ info: undefined
292
+ },
293
+
294
'snmp': {
295
title: 'SNMP',
296
icon: '<i class="fa fa-random" aria-hidden="true"></i>',
@@ -1324,5 +1330,28 @@ netdataDashboard.context = {
1330
info: 'These tags are optional and describe some error conditions which occured during response delivery (if any). ' +
1331
'<code>ABORTED</code> when the response was not completed due to the connection being aborted (usually by the client). ' +
1332
'<code>TIMEOUT</code>, when the response was not completed due to a connection timeout.'
1333
+ },
1334
+
1335
+ // ------------------------------------------------------------------------
1336
+ // Fronius Solar Power
1337
+
1338
+ 'fronius.power': {
1339
+ info: 'Positive <code>Grid</code> values mean that power is coming from the grid. Negative values are excess power that is going back into the grid, possibly selling it. ' +
1340
+ '<code>Photovoltaics</code> is the power generated from the solar panels. ' +
1341
+ '<code>Accumulator</code> is the stored power in the accumulator, if one is present.'
1342
+ },
1343
+
1344
+ 'fronius.autonomy': {
1345
+ commonMin: true,
1346
+ commonMax: true,
1347
+ valueRange: "[0, 100]",
1348
+ info: 'The <code>Autonomy</code> is the percentage of how autonomous the installation is. An autonomy of 100 % means that the installation is producing more energy than it is needed. ' +
1349
+ 'The <code>Self consumption</code> indicates the ratio between the current power generated and the current load. When it reaches 100 %, the <code>Autonomy</code> declines, since the solar panels can not produce enough energy and need support from the grid.'
1350
+ },
1351
+
1352
+ 'fronius.energy.today': {
1353
+ commonMin: true,
1354
+ commonMax: true,
1355
+ valueRange: "[0, null]"
1356
}
1357
};